24 апр. 2010 г.

Русскоязычные поддомены BlogSpot

Для создания адреса блога можно использовать русский поддомен домена blogspot.com.
Для этого нужно перевести желаемое занвание в IDN-форму и в качестве желаемого поддомена ввести именно её.
Например для того, чтобы зарегистрировать домен день.blogspot.com:
  1. Перейти на сайт конвертации доменов в IDN
  2. В поле "текст на национальном языке" ввести слово день.
  3. Нажать клавишу >>>
  4. Взять текст из поля "Текст в кодировке punycide" и вставить его в качестве желаемого поддомена.
Можно проверить: http://день.blogspot.com/

18 апр. 2010 г.

Усилок

Давным давно в усилке была проблема - не выключается.
Дошли руки: разобрал. Оказалось, что сгорела какая-то деталь, соединяющая провода параллельно с выключателем. Выломал. Работает.

12 апр. 2010 г.

Фильтрация по элементам массива в хранилище Google App Engine

Если в поле класса хранится массив каких-то значений, то при фильтрации по полю, содержащему массив выполняется фильтрация по значениям этого массива и элемент возвращается если хотя бы один из элементов массива соответствует условию.
Например
@PersistenceCapable
public class Test {
@PrimaryKey
@Persistent(valueStrategy=IdGeneratorStrategy.IDENTITY)
Key id;
@Persistent
ArrayList arr = new ArrayList();
public ArrayList getArr(){
return arr;
}
}
Пусть у нас есть 3 элемента, со значениями arr: (100,200,300), (200,300,400), (400,500,600)
По запросу: SELECT * FROM Test WHERE arr = 200
Будут выбраны первые 2 элемента.
По запросу: SELECT * FROM Test WHERE arr > 300
Будут выбраны элементы 2 и 3.
По запросу: SELECT * FROM Test WHERE arr = 100
Будет выбран первый элемент.

JDO в Google App Engine

Несколько месяцев назад инициализация PersistentManagerFactory занимала около 20 секунд. Сейчас это время сократилось до 5-7 секунд.
UPDATE: 2-3 секунды, еще 2-3 требовалось на компиляцию и запуск самого приложения.

7 апр. 2010 г.

Google App Engine, двойная проверка особо важных данных

Подробно изоляции транзакций описаны в документации
Англоязычная статья
Из них следует краткий вывод:
Есть небольшая задержка по времени между обновлением данных в хранилище и обновлением индекса, но данные всегда возвращаются из хранилища, поэтому иногда можно получить что-то, что не удовлетворяет условиям запроса и если критически важно быть уверенным, что все что вы получили соответствует параметрам запроса - проверяйте данные еще раз при их обработке.
Подробности хорошо описаны в документации.

2 апр. 2010 г.

Google Guice, начало.

Отступление - по звучению напоминает Урфин-Джус из какой-то там части сказки "Изумрудный город".
Guice - Java-библиотека, помогающая использовать стиль программирования внедрение зависимостей (Dependency injection).
В самом простом случае - вам нужно иметь ссылку на какой-то определенный объект (например настройки) в разных частях программы.
public class Settings {     
   static int count = 0;      
   int getVersion()     {         
       ++count;         
       return count;     
   } 
}  
Раньше я это решал методом создания статического класса и прописывания всех настроек в статических полях этого класса.
Это в общем-то не доставляет неудобств, если не нужно проводить модульного тестирования программы с разными настройками или где-то иметь немножко другие настройки, но зато это самый простой пример использования инъекций.
Чтобы иметь этот класс у себя обычным образом нужно создать новый объект
Settings settings = new Settings();  
Что нужно сделать, чтобы создать этот объект через Guice? 1. Нужно создать объект-инъектор 2. Чтобы создать объект-инъектор нужна реализация класса AbstractModule. Для этого нужно переопределить метод configure. Для начала реализация будет самой простой - пустой.

public class GuiceModule extends AbstractModule {
 @Override
 protected void configure() {
 }
}
(Недописано, т.к. думаю что не особо нужно - я разобрался и примеры есть. У кого будет потребность - оставьте комментарий, статью допишу)

Непривычности Google App Engine 2

Занимаемое место

Есть 50 тыс записей о товарах вида: название, номенкралутрный номер, 3 цены, наличие на складе и т.п., текстовый файл для импорта в кодировке Windows-1251 занимает 4.5 МБ.
После импорта в базу GAE по данным статистики они стали занимать 15 МБ.
Потом посмотрел не на статистику, а на детализацию квоты по занимаемому месту:По квоте показывается, что мои данные занимают 100 МБ места.
В итоге: в статистике данных метаданные это видимо только данные о структуре записей, но не индексы. Сотрудник Google подтверждает, что индексы действительно могут занимать в десятки раз больше места, чем сами данные, особенно если используется много свойств, у них длинные названия и у сущности длинное название.
По умолчанию при присваиванию значения свойству для каждого свойства его значение записывается в индекс, чтобы задать свойство без занесения его значения в индекс в Java нужно пользоваться методом setUnindexedProperty. При этом чтобы удалить из индекса значения уже созданных объектов нужно заново сохранить этот объект, установив значение без индекса.
Работа с хранилищем
Видимо на предыдущем эксперименте основное время было затрачено на удаление записей, т.к. это оказалось довольно дорогостоящей операцией на удаление 50 тыс. записей с первичным ключем и 10-ю индексированными полями полями ушло 2.16 часа процессорного времени Datastore, а оно входит в общую процессорную нагрузку.
На импорт этих же записей без индексов (кроме обязтельного первичного ключа) со вставкой по одному объекту потребовалось 0.68 часа процессорного времени хранилища. При вставке пачками по 10 штук скорость импорта возросла примерно в 5 раз, и немного возросло затраченное процессорное время хранилища - на импорт пачками по 10 штук потребовалось 0.75 часа машинного времени. Возможно это потому что я уже был на границе суточной квоты и у меня была надпись Limited. Возможно произошли какие-то изменение в структуре хранения данных приложения, например часть данных переместилась на другой сервер и обращение стало занимать больше ресурсов.
Почему-то при активной работе с хранилищем полезная скорость его работы снижается.
Уменьшении количества объектов в хранилище скорость их удаления снижается, а при увеличении последовательном удалении записей при 15-секундной работе сервлета удаляется сначала 2500 записей за вызов, потом снижается до 1500 объектов за вызов, затем до 1100 объектов/вызов.
Фактическая скорость удаления (т.е. количество объектов, удаленных в единицу времени) объектов не зависит от наличия индексов. В обоих случаях все 50 тыс. объектов были удалены за 33 15-секундных вызова сервлетая, скорость удаления снижалась одинаково.
Зато отсутствие индексов положительно сказалось на процессорном времени, завтрачиваемом на удаление хранилищем. Для удаления 50. тыс. объектов с 10-ю индексами потребовалось 2.16 часов процессорного времени хранилища, а для удаления их же, но с индексом только по первичному ключу - 0.32 часа.
Хотя все равно получается, что операции вставки/удаления в хранилище это дорогие по времени операции.
Импорт тех же записей в MySQL одиночными запросами занимал 2-5 минут.
Итак - с хранилищем Datastore нельзя работать как с привычными базы данных - это и неудобно и занимает очень много ресурсов.
В общем-то Google и сам говорит, что один объект не поддерживает более пяти записей в секунду, но обещает очень быстрые выборки.
Тогда в чем плюс и почему Google App Engine интересен?
Google обещает что эта скорость не будет падать при увеличении объема данных или количества параллельных запросов и не будет зависеть от соседей по серверу.
Сброс значения квот
Иногда задерживается. Например сегодня у меня сброс задержался примерно на 1.5 часа, так что впритык к квотам лучше не работать.

1 апр. 2010 г.

Внедрение зависимостей (Dependency Injection)

При написании программ мне давно уже не нравилось использовать какие-то общие статические класса для обращения к базе данных например, но до последнего времени альтернативы не знал.
Посмотрев видео с Google Developer Days 2009 о создании Google Wave вынес для себя подход к разработке с использованием отдельной шины событий, по возможности хранение в каждом контроле собственной копии объекта, с которым он связан и принцип внедрения зависимостей (dependency injection).
Принцип внедрения зависимостей гласит - все объекты, от которых зависит данный должны в него передаваться. В объекте не должны создаваться какие-то объекты напрямую, отсутствуют обращения к статическим переменным/константам.
Т.е. например у нас есть форма, показывающая и изменяющая объект в базе данных. Внутри этой формы не должно быть вызовов вроде Common.getDB(). - объект для работы с базой данных передается в него через конструктор (предпочтительно) или устанавливается через вызов метода, но не берется из какого-то внешнего класса внутри самой формы и не создается внутри формы.
Так же все дочерние элементы, которые создаются в объекте.
При создании дочерних объектов конструктор объекта не вызывается напрямую, а создается фабрикой внедрения зависимостей (Injector).
Создание объектов через фабрику внедрения зависимостей позволяет:
1. Указывать конкретные типы создающихся объектов где-то в другом месте (аннотация в коде, конфигурационный файл, вызов методов и т.п.).
2. Опустить процесс написания собственных фабрик и передачи кучи параметров из одного объекта в другой (объект настроек приложения, объект для работы с БД и т.п.)
Первый пункт позволяет облегчить создание модульных тестов: вместо всех объектов, от которых зависит проверяемый объект ему передаются заглушки, которые просто фиксируют что сделал объект и простейшим образом реализуют нужные интерфейсы. Это позволяет тестировать каждый объект отдельно, без связи с остальными объектами
Второй пункт сильно снижает рутинное написание фабрик объектов.
В этом же видео были упомянуты разработки Google для простого реализации принципе внедрения зависимостей:
Guice для Java
Gin для GWT