Wednesday, September 30, 2009

Портируемость С#(ложка дегтя)

Продолжение поста .
Портируемость С# достаточно иллюзорна, да есть реализация под linux, но основа любого приложения не язык на котором она написана, а логика работы и интерфейс общения с внешним миром. Вот в это и есть проблемы приложение под C#(десктоп, про ASP судить не могу) пишется обычно с использованием WinForms который является сугубо пропретарным продуктом. В результате мы получаем приложение которое под Mono не только выглядит по другому (выглядит как белая ворона под Linux, не интегрируется не в один диспетчер окон), имеет другую логику работы и другие глюки фичи(частично это вызвано тем что сделать точно также как Microsoft нельзя: закрыты полные спецификации, но и нежелательно, сразу попадаем под область возможных судебных тяжб, реализуем все заново). В общем это не так страшно - но может привести к большому проценту переписанного кода.

Проблемы лицензии при создании приложений на C#.

Сам фреймворк бесплатен для использования в программах, отчислений за его использование как мне известно не нужно. Разрабатывать можно в SharpDevelop с использованием для создания пакетов установки Wix это покрывает 90% потребностей при разработке. Если нужно студия можно использовать Express версию (для которой есть одно существенное отличие - отсутствие пакетов установки) в сумме это дает полное покрытие по средствам разработки.

В дальнейшем я вижу только проблемы с совместимостью реализаций .Net на новых версиях mono(в общем-то, это не так страшно, можно найти версию когда все работает и не обновляться) и возможное требование отчислений за использование в разработке от Microsoft(что немного хуже, но это дает время чтобы портировать на другой язык и фреймворк, а пока пытаться использовать mono).

В общем как временное решение использовать можно - но лучше использовать действительно портируемые языки без возможных изменений лицензирования или хотя-бы использовать Gtk# вместо WinForms.

P.S. :
  • Обратите внимание стили окошек под mono отличаются от подразумеваемых в WinForms (BorderStyle), могут быть проблемы с диалогами они появляются под формочками, а так как на панели задач они не отображаются, может казаться, что приложение наглухо зависло.
  • Может и не нужно никакое портирование попробуйте запустить под wine с установленным .Net(у меня не получилось - приложение просто выходило без ошибок , но с большим количеством warn - но попробовать стоит).

Saturday, September 19, 2009

HAL и монтирование устройств

В последнее время у меня при попытке при попытке монтирования устройств пользователем появлялось сообщение:
org.freedesktop.hal.storage.mount-removable no <-- (action, result)
Лечиться исправление файла /etc/PolicyKit/PolicyKit.conf.

Thursday, September 10, 2009

Неоднозначности Google AppEngine

Мелкие несоответствия в документации Google AppEngine
или мелкие, но неприятные особености.

Загрузка файлов.

  • В документации в примере работы с фотографиями указано, что по умолчанию для параметров загрузки файлов выдается их содержимое. В действительности выдается исходное имя файла, поэтому нужно вместо:
     self.request.get('uploadfile') 
    , использовать
     self.request.params.get('cvs').file.read() 

Кодировка строк.

  • Параметры возвращаемые self.request.get() возвращаются в виде unicode строк;
  • В базу данных тоже нужно сохранять unicode строки;
  • При редиректе нужно использовать для строк содержащих символы не входящие в ASCII выражение вида:
    sub_path = self.request.get('path')
    self.redirect('/forum?path=' + cgi.escape(sub_path.encode('utf-8')))
    , то есть перед выполнением редиректа нужно преобразовать в обычную строку.

Особенности базы данных

  • Пока обнаружил только, что желательно добавлять и удалять маленькими порциями. В первом случае можно наткнуться на ограничение во времени (5 секунд) и нагрузке при обработке запроса. В втором случае удалить более 300 объектов за раз нельзя. Цифры примерные - точные цифры получить не пытался, известно только, что за зараз можно добавить 600 объектов и раза в два меньше объектов удалить.
  • Нагрузки на процессорное время при первом получении результатов (не созданы индексы) может достигать на простых операциях вида: получить первые 25 результатов с сортировкой по дате ключу, может занять до 10 абстрактных секунд(30 секунд реальных) при последующих запросах значения падают на порядок.
  • Добавление 600 записей может использовать до 1% процессорного времени выданного для бесплатного аккаунта.
  • База основана на технологии map/reduce, и не поддерживает команды SQL кроме select. Но удобнее, как по мне, использовать нативные методы order, filter, put, fetch.
  • Можно только сравнивать на равенство больше/меньше и включение(in), операции like и под запросы не поддерживаются.
  • Для реализации операций соответствия признаку (или поиск слов, тегов) можно использовать разбиение исходного предложения на минимальные единицы с последующим сохранением этого списка, как отдельного поля в записи (можно в поле записи сохранять список), а потом при поиске использовать вхождение. Конечно, это немного не то, если нужен like, но вполне быстро срабатывает.
  • Включение работает как пересечение, то есть если есть общие элементы, то возвращается истина.
В общей сумме бесплатного аккаунта вполне хватает для маленького тестового сайтика, чтобы поэкспериментировать. В минимальной поставке идет(без дополнительных телодвижений): Django 0.96(используется как шаблонизатор), поддержка базы данных, memcached и библиотека преобразования изображений.

Monday, September 7, 2009

Уникальные идентификаторы для контента

В принципе можно решать как общую задачу создания уникальных идентификаторов:
  • использовать данные генератора случайных чисел (не удобно так как не возможно четко контролировать результат);
  • использовать псевдослучайные значения, например время, процесс/поток с последующим преобразованием в символьное имя;
  • символьное имя очень полезно - так как позволяет лучше при отладке отличать идентификаторы (числа в любом виде хуже отображают отличия);
, а можно учитывать специфику:
  • имена должны поддерживаться файловой системой(запрет на использование спец символов);
  • максимально короткие эффективные имена(снижение затрат памяти), использование всего пространства допустимых символов,
  • близкие по времени создания и исходному значению имена должны быть максимально случайны по результату - то есть использовать максимально эффективный хеш-функцию - обычно достигается использованием хеш значений от псевдослучайных факторов времени создания, процесса/потока и идентификатора хранилища;
  • решение противоречивой в общем-то задачи:
    • максимального разброса имени контента для сохранения;
    • и возможности по имени определить максимально быстро наиболее вероятное хранилище в распределенной системе можно использовать 2 имени - внутреннее и внешнее;
    • внутреннее должно быть максимально эффективно дробить множество доступных вариантов размещения в локальной системе с разбиением на подкатологи с минимальной вероятностью превышения пределов на одновременное количество вложенных каталогов. Это ограничение возникает как из-за временных затрат при работе с большими каталогами, вытекающее иногда в невозможность добавления данных в каталог, и удобства конечного владельца системы, хоть и редко, но удобнее ходить по маленьким каталогам. Также при максимальном разбросе можно разместить часть каталогов на другом разделе и реализовать дешёвое подобие RAID.
    • внешнее - не противоречить правилам для протокола доступа, например не содержать спец символов специфичных для http и html разметки. Позволять легко определить максимально вероятное место расположения в распределенной системе для быстрого выявления не корректно отвечающей части, также при дублировании на другие ресурсы - можно легко удалить данные не специфичные узлу при окончании ресурсов.
Очень желательно, чтобы в внутреннем имени присутствовали хеш функция от размера данных (можно просто выделение остатка от деления на какое-то число с получением base64 + как подкаталог base64 от полного размера) и его контента (для снижение количества коллизий лучше сразу два хеш значения от контента). В результате можно быстро найти подобный контент найдя подобную запись в списке преобразований внутреннее имя <-> внешнее имя или, что должно работать гораздо быстрее при большом количестве разнообразного контента, присутствия такого каталога на диске. В дальнейшем можно проверить его содержимого на совпадение с добавляемыми данными. Как результат мы не будем забивать хранилище дубликатами и при желании сможем сообщать, что пользователь пытается снизить энтропию вселенной.

Tuesday, August 18, 2009

Оптимизация размера картинок

Для оптимизации размера фотографий без потери качества и сохранением размеров можно использовать jpegoptim - на маленьких фотографиях получаеться около 60% уменьшения занимаемого под фото места, для больших фотографий полученых без преобразований - экономия около 1%.

Например:
find . -name data-\* -exec jpegoptim --strip-all '{}' \;
Более подробно можно посмотреть рекомендации google или воспользоваться их плагином для анализа произодительности сайтов (достаточное большое количество проверяемых параметров, не только размер фотографий).

P.S.:
  • Примерно техже результов можно добиться используя jpegtran -optimize, размер файла в результате получаеться один и тотже.
  • Для png можно использовать optipng:
    find . -name \*.png -exec optipng -o7 '{}' \;

Friday, August 14, 2009

Рейтинг запросов

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

cat result.log |sort > sorted.log
uniq -c sorted.log |sort -n -r |more


Можно использовать чтобы узнать наиболее популярные запросы к серверу.

Wednesday, July 29, 2009

Добавление поддержки CSS в GtkHtml

В общем идея:
  • сейчас в gtkhtml - используется некое подобие SAX парсера, на основе которого сложно создать что-то подобное поддержке CSS. Конечно можно, так как все таки дерево элементов существует, но долго и есть другой вариант;
  • нужно заменить парсер на использование libxml;
  • заменить рендеринг на использующий XmlTree
  • использовать рендеринг в два прохода:
    • первичный рендеринг только html без css c созданием запросов на css
    • вторичный при доступности css применять его к дереву и вызывать перерисовку;
  • в теории мы получим немного более медленный рендеринг - запускающийся только после получения полного дерева, сейчас редеринг идет в параллель с парсингом.
Сейчас реализовал только замену парсера(мой fork на github) и тестовые приложения для проверки применения css. Для парсинга используется libcroco. За основу тестовых приложений взят код - позволяющий применить css к xml c использованием пространств имен.