Uniвсячина

понемножку о Linux и программировании

RSpec в 26 строк на Scheme

Развлекаюсь во всю с языком Scheme. Кто не знает, Scheme — это такой диалект Lisp’а. В настоящей момент более-менее дожили до наших лет только два диалекта: Common Lisp и Scheme. Common Lisp — большой динозавр на которого за 50 лет навешали дофига всего (включаю свою ОО-систему – CLOS). Scheme напротив, как элегантная лань, небольшой ядро примитивов, на основе которых реализуется все остальное. Предпоследний стандарт языка Scheme (R5RS) занимал всего порядка 50 страниц (сравните с тысячью страниц для стандарта C++).

Так вот, одно время было модно реализовывать популярный BDD-фреймворк RSpec, написанный на Ruby, на разных языках. Я решил сделать прототип на Scheme. Получилось кратко и элегантно. А возможно даже более гибко. Кстати без всякого ООП :)

(require-extension syntax-case)

(define-syntax desc
  (syntax-rules (it should)
    ((_ doc subject (it it-doc matcher ...) ...)
     (begin (display doc)
            (newline)
            (let ((it-value subject))
              (begin (display (string-append "  - " it-doc))
                     (if (and (matcher it-value) ...)
                         (display " (passed)")
                         (display " (failed)"))
                     (newline))
              ...)))))

(define-syntax should
  (syntax-rules ()
    ((_ predicate)
     (lambda (subject) (predicate subject)))
    ((_ predicate arg1 ...)
     (lambda (subject) (predicate subject arg1 ...)))))

(define-syntax should-not
  (syntax-rules ()
    ((_ predicate)
     (lambda (subject) (not (predicate subject))))
    ((_ predicate arg1 ...)
     (lambda (subject) (not (predicate subject arg1 ...))))))
;; определим собственный матчер
(define (good-number? n)
  (= n 5))

(desc "Given natural number"
      5
      (it "should be integer"
          (should integer?))
      (it "should be positive"
          (should positive?))
      (it "should be good number"
          (should good-number?))
      (it "should not be less than 0"
          (should-not < 0))
      (it "should not be inexact"
          (should-not inexact?)))

При запуске выводит на экран:

Given natural number
  - should be integer (passed)
  - should be positive (passed)
  - should be good number (passed)
  - should not be less than 0 (passed)
  - should not be inexact (passed)

Запускать на Chicken Scheme.

Учебник по pgpool-II

Не могу пройти мимо и не попиарить перевод учебного руководства по pgpool-II.

Кто не знает, pgpool-II — это замечательная тулза для postgresql, которая позволяет делать:

  1. репликацию (в том числе, с автоматическим переключением на резервный stand-by сервер);
  2. online-бэкап;
  3. pooling коннектов;
  4. очередь соединений;
  5. балансировку SELECT-запросов на несколько postgresql-серверов;
  6. разбивать запросы, для параллельного выполнения над большими объемами данных.

MySQL vs PostgreSQL в ActiveRecord

Если вы пишете мультитредовые приложения на Ruby/Rails с использованием ActiveRecord, то вы не должны выбирать между MySQL и PostgreSQL. Выбор известен заранее.

Как известно, Ruby обладает таким противным свойством, как GIL в C-extensions. Драйвер базы данных — это несомненно C-extension (по крайней мере, это утверждения справедливо для MySQL и PostgreSQL). Так что, если вы написали multithreading приложение, которое активно работает с базой через ActiveRecord и ждете, что использование нескольких ниток позволит лучше использовать процессорное время, то тех из вас, кто пользует MySQL, я спешу разочаровать — MySQL-драйвер будет блокировать ваш тред на все время выполнения sql-запроса.

А вот пользователей PostgreSQL спешу поздравить. ActiveRecord будет использовать async-вызовы драйвера и вы в полной мере насладитесь ожидаемым эффектом.

P.S. Да-да, я знаю о такой поделке, как драйвер MySqlPlus. Но лично мне, как-то ссыкотно его запускать на продакшен.

Как отключить кэш при тестировании Rails-приложений

Столкнулся с проблемой в одном из разрабатываемых Rails-приложений. Интеграционные тесты в cucumber проходят по одному, но при запуске всей кучей, начинают падать в failed.

Проблема оказалась в кэшировании данных через Rails.cache. Так как, по-моему разумению, в окружении test всякое кэширование должно быть отключено, то пришлось наваять “заглушку” для кэша:

config/environments/test.rb:

config.cache_store = :dummy_store

lib/dummy_store.rb:

class DummyStore < ActiveSupport::Cache::Store

  def initialize
  end

  def read(name, options = nil)
    super
  end

  def write(name, value, options = nil)
    super
  end

  def delete(name, options = nil)
    super
  end

  def delete_matched(matcher, options = nil)
    super
  end
end

Удаленная перезагрузка Linux

На днях столкнулся с ошибкой в файловой системе, из-за которой корневая FS переходила в режим read-only. Команда reboot в таком режиме работает крайне неадекватно: убивает половину процессов, но в ребут сервер не посылает.

Как известно, у Linux есть “волшебные” сочетания клавиш, которые позволяют подавать команды напрямую ядру. Например:

  • Alt+SysRq+k — убить все процессы.
  • Alt+SysRq+s — сохранить все дисковые буферы.
  • Alt+SysRq+b — перезагрузить ОС.

Можно так же ознакомится с полным списком команд.

В нашем случае, нас интересует команда Alt+SysRq+b. Однако, когда у вас доступ к серверу только по SSH, нажать подобную комбинация не так то легко. К счастью, создатели Linux уже позаботились о нас:

echo 1 > /proc/sys/kernel/sysrq
echo b > /proc/sysrq-trigger

Таким же образом, можно посылать и другие “волшебные” команды.