четверг, февраля 22, 2007

Идеальное хранилище

Вот так высокопарно :) Разумеется, ничего идеального нет, но то, о чем я сегодня пишу, в некотором смысле тянет на это определение ;) Речь пойдет о хранении настроек приложения, как частном случае. Как известно, для хранения настроек изначально (аж со времен DOS) использовались т.н. ini-файлы, текстовые файлы с незамысловатой структурой. Решение очень простое и даже примитивное. Примитивность заключалась в неструктурированности и непизированности хранимых значений, и именно из-за нетипизированности были основные проблемы (конечно, если разработчику не лень в каждом месте выполнять вручную конвертирование типов из строкового представления, для него это не проблема). Потом Майкрософт сказала, что ini-файлы - прошлый век, и всем пора пользоваться реестром (единым системным хранилищем). Там, и типизация, и возможность "структурного" хранения и вообще реестр - rulezzz!  И толпы программистов-леммингов кинулись претворять в жизнь призыв Большого Билла. Но, как оказалось, структурированность реестра не относилась к типизации данных (их по прежнему приходилось хранить в "плоском" виде), структурировать можно было только расположение (что, собственно, присутствовало и в ini-файлах).  Разработчики привыкшие к такому положению дел еще со времен ini-файлов, кажется, не особенно и растроились (запросто храня массивы и структуры в виде бинарных блоков). Но время шло и пользователи стали замечать, что файлы реестра пухнут и, как следствие, система уже не так резва, как после установки. Оказалось, что всему виной приложения оставляющие, даже после своего удаление, в реестре груды мусора. Эта проблема породила целый класс программ-чистильщиков реестра (авторы, наверное, благодарны Большому Биллу). [Кстати, с приходом .Net изменилось отношение Майкрософт к вопросу хранения настроек, теперь они не рекомендуют использовать реестр и снова предлагают хранить все в файлах (все возвращается на круги своя ;))] Потом появилась идея, хранить настройки в файлах формата XML. Идея совсем не плоха, т.к. структурирование заложено в саму суть формата, но беда (не формата, как такового, а идеи хранения в нем типизированных данных) в том, что типизация в формате не предусмотрена (еще раз скажу, что это не проблема самого формата), конечно существуют различные механизмы описания, типа DTD, но для задачи хранения настроек это слишком... Как вариант, можно пойти своим путем (так сделала сама Майкрософт для своего продукта Virtual PC 2004) и хранить в xml-файлах информацию о типах элементов (благо формат позволяет делать это весьма элегантно). Я же, хочу рассказать еще об одном варианте "своего пути", личном ;) Так случилось, что мне пришлось писать собственную реализацию протокола XML-RPC, и сейчас, софт, который пишется, пишется с прицелом на этот протокол. Так вот, для хранения настроек и некоторых файлов с данными, было решено использовать формат пакетов XML-RPC (A, что может быть лучше? Тут, и строгая типизация, и богатый набор самих типов (да еще и парсинг уже написан и отлажен)). Сам протокол имеет только два типа пакетов methodCall и methodResponse, настройки логичнее хранить во втором, но чтоб не смущать пользователей любящих подкрутить что-нибудь руками тэгом <methodResponse>, я добавил третий тип пакета value (это не потребовало сколь нибудь значительной переделки генератора пакетов т.к. элементы value в любом случае сериализуются), который аналогичен пакету methodResponse, но где корневым элементом является value.

воскресенье, февраля 18, 2007

Очередной баг

Сегодня наткнулся на интересную особенность работы конструкторов записей. Имеем запись с полем типа Variant. В конструкторе, который, как известно, может вызываться сколь угодно раз для объекта/записи, присваиваем полю интерфейс получаемый из вновь создаваемого объекта. По идее, должно произойти освобождение старого объекта (если вызов не первый) т.к. ссылка на его интерфейс теряется, а затем назначение полю нового значения. Но при входе в конструктор, благодаря компилятору, поле получает значение Unassigned, в результате чего, мы имеем утечку памяти.

четверг, февраля 08, 2007

POPFile 0.22.4. Осьминог жукастый

Где-то, на просторах инета наткнулся на классификатор почты, POPFile, использующий теорему Байеса (Bayes) для отделения мух от котлет :) Нашел несколько хвалебных отзывов от его пользователей (говорят фильтрует аж 99.9% процентов спама), и самое главное, увидел, что он имеет XML-RPC API для взаимодействия с внешним миром. Не смог пройти мимо и не попробовать "повзаимодействовать" :) Качнув и установив его на виртуальную машину,  активировал работу XML-RPC API для внешних подключений (по умолчанию XML-RPC отключен). Дело за клиентом! По первому попавшемуся примеру сваял маленький пробник для перечисления корзин классификатора. И тут меня ждал неприятный сюрприз... Ошибшись в имени метода (пропустил одну букву) я получил в ответе некорректную (не соответствующую спецификации XML-RPC) fault-структуру, где член faultCode имел строковый тип... Выходит, используемая им перловая реализация (XMLRPC::Lite если я не ошибаюсь) кривая, коли допускает подобные вольности. Вот такие дела, авторам отпишусь :)

P.S. Вот и делай людям добро ;) Попытался отрапортовать об ошибке, так оказалось, для этого еще и на SourceForge'е нужно регистрироваться. Ну уж нет :)

P.P.S. На вызов метода release_session_key отдается структура, также не соответствующая спецификации XML-RPC (тэг <params> не имеет обязательных дочерних элементов).

вторник, февраля 06, 2007

Неудавшийся поиск

Что-то я ни как не могу найти фришный (собственно и платных не видел) монитор для XML-RPC :( Не просто проксю, которая будет показывать тела пакетов, а именно полноценный монитор с парсингом сообщений и раскладыванием по полочкам передаваемых значений (в древовидную структуру например). Что-то вроде майкрософтовского SOAP listener'а (вроде так называется). А если у него окажется еще и поддержка boxcarring'а и introspection'а, то ваще будет рай :) Уж больно не хочется самому писать...

четверг, февраля 01, 2007

"Приведение" типов

Правда не совсем приведение... Встала задача получить из TMemoryStream строку. Самый простой путь, он же и самый не эффективный,  задать строке размер SetLength и потом просто скопировать память с помощью Move. Неэффективность налицо: двукратно увеличеное требование к памяти и время на копирование. Но есть вариант проще:

  Type

TOpenedMemoryStream = Class(TMemoryStream);

Var

Data : PChar;

...

With TOpenedMemoryStream(AStream) Do
Begin

// Если выделенной памяти ровно столько сколько требуется потоку
// (обычно больше т.к. память выделяется блоками по 8192 байт)
// увеличиваем количество выделенной памяти не изменяя размера потока
If Capacity = Size Then
Capacity := Capacity + 1;

// Сразу за блоком, занимаемым потоком, записываем признак конца строки
// и сохраняем указатель на блок памяти для для последующей обработки
PByte(Integer(Memory) + Size)^ := 0;
Data := Memory;

End;

Теперь переменную Data можно приводить к строковому типу :)

Исходники

На домашней страничке выложен архив (~8Kb) содержащий модули и шаблон для создания мультиформенного приложения (MS Office 200 like).