суббота, 5 февраля 2011 г.

Особенности конкурентной записи/чтения файлов в perl + NFS

Рассмотрю буквально парочку малоизвестных нюансов/подводных камней.

Мало кто знает, что для вычитки файла в строку можно использовать такой код:

my $content = do {local (@ARGV, $/) = $filename; <ARGV> };
За объяснениями в perldoc perlvar  и поиск по ARGV.

Такой подход использовался и в File::Slurp. В данной ситуации не просходит flock, это важно учитывать если Вы этот файл еще и пишите другим процессом . Проблему конкурентной записи можно решить и без flock, просто нужно операцию записи сделать атомарной(File::Slurp поддерживает для этих целей флаг "atomic").

Идея заключается в следующем:
  1. Создается уникальный временный файл и в него пишутся данные
  2. Временный файл переименовывается в целевой файл. Операция rename в большинстве ОС - атомарная. 
И казалось бы все отлично, но лишь до того момента когда вы начнете использовать NFS :)

Операция rename в NFS - атомарная, но есть следующий нюанс. Если вы делаете rename и файл назначения уже существует, то сначала удаляется файл назначения, а затем лишь происходит rename. И это ДВЕ  ОТДЕЛЬНЫЕ операции.

В результате если у Вас один процесс читает файл, а другой его периодически обновляет, то возможна ситуация когда читающий процесс просто не увидит файл. 

суббота, 29 января 2011 г.

Perl IDE: Eclipse + Epic

Perl IDE
Посмотрел видео с Perl-воркшопа «Saint Perl — 2» (Санкт-Петербург). Доклад "Perl IDEs" Шафиева Наима.

Я в свое время поигрался почти со всеми перечисленными в докладе IDE и редакторами (кроме Kephra и Emacs) и сделал выбор в пользу Eclipse + Epic.

Сразу немного критики в сторону докладчика, который заявил, что  Epic is deprecated и с 2008 без обновлений. Я пользуюсь Epic и наблюдаю там движение.
Версия 0.6.35 вышла в 2009-07-27. Сейчас у меня установлена версия Epic 0.6.39
Если зайти на сайт проекта, то можно увидеть, что последний коммит был сделан 2011-01-16.

Почему ...
Почему не Vim?
Замарочки с конфигом, а я хочу, чтобы все работало с коробки. Кроме того, меня убивают в Vim некоторые вещи при работе с буферами. В общем моя продуктивность при работе в Vim с большими проектами падает. У меня был очень толковый конфиг и я работал в Vim больше месяца по 8 часов в день, возможно это не так много, но я не готов тратить больше времени лишь для того, чтобы подстроить себя под редактор.

среда, 5 января 2011 г.

Как Perl стал современным(Modern)?!

Смотрим видео про то, как Perl стал современным ;)

Get the Flash Player to see this player.


среда, 22 декабря 2010 г.

Ура, товарищи. Вышел Mojolicious 1.0

Список изменений по этой ссылке

Хотя в твиттере Себастьяна видим:
"#mojolicious 1.0 is scheduled for december 26! #perl"

среда, 1 декабря 2010 г.

Чем плох eval?!

Чем плох eval?!
В perl, как всем известно, имеется 2 варианта вызова функции eval. Строковый eval для компиляции и выполнения кода на лету и блочный eval.
Нас интересует блочный eval.
Часто встречается такой вот код:


eval { 
  # some code 
  die "error"; 
  # some code  
}; 

if ($@) { 
    print "Error [$@] occured!"; 
}

Это вполне стандартный код, но есть ряд недостатков связанных и с использованием глобальной переменной $@.
Потенциальная проблема #1
Если кто-то локализировал переменную $@, то мы не сможем перехватить исключение. В этом коде мы не видим ошибки.


sub do_die { 
    die "Error"; 
} 

eval { 
    local $@;
    do_die(); 
}; 

if ($@) { 
    print "Error [$@] Occured!"; 
} 


Потенциальная проблема #2
Если в деструкторе используется eval, то скорее всего мы не перехватим исключение. Пример:

package Object;
sub new { 
    my $class = shift; 
    my $self  = {}; 
    bless $self, $class; 
}

sub DESTROY {
    eval { 
        # some clean code 
    } 
} 

package main; 
eval { 
    my $obj = Object->new(); 
    die  "Error"; 
}; 

if ($@) { 
    print "Error [$@] Occured!";
} 

  Деструктор с eval-ом может быть в ком-то модуле с CPANа и Вы просто не будете знать про это.
Потенциальная проблема #3
 $@ может содержать объект, которые в булевом контексте вернет ложь.

Решение
В связи со всем вышесказанным, рекомендую использовать  модуль Try::Tiny либо TryCatch. Они позволят Вам  избежать описанных проблем в будущем  и предоставят удобные и понятные синтаксический конструкции(try{}catch{} finally{}).  

Я использую Try::Tiny, он мне нравится своей минималистичностью и отсутствием внешних зависимостей. 

Вот пример кода с Try::Tiny. Красиво и надежно :).
# handle errors with a catch handler
try {
    die "foo";
}
catch {
    warn "caught error: $_";    # not $@
};

# just silence errors
try {
    die "foo";
};
Более доходчиво про это все написано в "perldoc Try::Tiny".

среда, 24 ноября 2010 г.

Пример приложения на Mojolicious ( не Lite )

Пример приложения на Mojolicious ( не Lite )
В интернете много всего уже сказано про Mojolicious::Lite, но сегодня про Mojolicious (не Lite). С фреймворком я только начал знакомится, поэтому смело критикуйте в комментариях. Для изучения фреймворака я решил написать прототип сервиса заметок. Сразу прошу не писать про XSRF,  я в курсе и это лишь прототип. Расписывать все я не буду, только ключевые моменты. Основную информацию Вы сможете почерпнуть непосредственно из кода.
Почему Mojolicious?
Mojolicious - очередной MVC веб-фрейворк. "Очередной велосипед, хоть и с более круглыми колесами", как кто-то он нем отозвался на одном из форумов.

четверг, 21 октября 2010 г.

Тестирование в Perl: Завершение теста при первой ошибке

Для меня стала открытием вот эта функция - Test::Most::bail_on_fail :)

Вкратце объясню зачем оно нужно.
В обычном режиме прогоняется все тесты, а затем выводится отчет. И потом приходится искать в логах нужное место для выяснения причин ошибок.

Если вы добавите в начало теста вызов Test::Most::bail_on_fail, то при первой же неудаче тест остановится. Теперь нас интересуют лишь последние сообщения в лог файле ;)