среда, 16 декабря 2009 г.

Subversion: Начало

Благодаря интуитивно понятному интерфейсу всяких программ и эклипсоплагинов создается впечатление, что знаешь как работать с свн. Но когда дело доходит до суровых консольных условий приходится читать svn book и с плачем гуглить.

Одна из самых неприятных задач возникающих в начале работы с subversion - преобразование обычной папки в рабочую копию. То есть когда уже имеется некое содержимое и цель - поместить это содержимое под контроль версий. Неприятна эта задача не потому, что ее сложно сделать, а потому, что делается она не так как подсказывает логика.

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

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

svnadmin create /var/svn-repos/content
cd /home/mycontent

Способ 1, не пугающий.

1. svn checkout file:///var/svn-repos/content .
2. svn add ./*
3. svn commit

Да-да, в первом шаге в конце отделенная пробелом точка (если ее не поставить то внутри /home/mycontent получим заверсионеную подпапку content).
Не пугающий, потому что здесь сам процесс помещения контента идет так, как и подсказывает разум. Однако, такой способ доступен только если после шага 0 вы не успели сделать роковой свн импорт (и ваш репозиторий пуст). Если сделали - выбираем способ для смелых.

Способ 2, для смелых.
На самом деле это полностью рабочий и безопасный способ (я его и использовал так как см выше).

1. svn import -m "Initial import" \
file:///var/svn-repos/content
2. svn checkout --force \
file:///var/svn-repos/content .

Способ этот для смелых, потому что создается впечатление, что свн перезаписывает все файлы (без параметра --force свн вежливо указывает на наличие файлов с таким же именем как и в репозитории). Однако по авторитетному заявлению в svn help checkout:
If the obstructing path is the same type (file or directory) as the corresponding path in the repository it becomes versioned but its contents are left 'as-is' in the working copy.

Вот так-то.

среда, 2 декабря 2009 г.

Wireless Toolkit: чистка записей в store

Вот и подошел к концу весьма интересный (но и столь же бесполезный, как оказалось впоследствии - см дальше) процесс разработки приложений на Java MicroEdition с использованием Sun Java Wireless Toolkit. К счастью в течение основной работы не приходилось заниматься настройкой-колупанием самого тулкита. Но вот сегодня настал и такой час.
Дело в том, что тулкит умеет эмулировать выполнение мидлета. Более того он умеет эмулировать и сохранение данных в record store. Что как раз и вышло боком, когда формат хранящихся данных был изменен. При старте мидлет отчаянно пытался зачитать все, что было сохранено прежде, как следствие - эксепшын.
Выход был очевиден - почистить эмулирующийся record store. Но как? Как ни странно ответ был найден обычным методом тыка без привлечения гугла.
В установленной папке Wireless Toolkit'а имеется папка bin и в этой папке лежит замечательный экзешник - utils.exe. В ней много всяких фич, в том числе и понадобившаяся мне - "Clean database".
Также стоит упомянуть такую фичу как "Sign midlet". Пока не пробовал, но если в мидлете имеются небезопасные операции (отправка сообщения, подключение в инет), то мидлет даже в эмуляторе начинает запрашивать разрешения пользователя. У меня в таких случаях эмулятор просто виснул. Поэтому чтобы избежать неприятных ситуаций лучше в эмуляторе засайнить мидлет.
Как раз с процессом sign'а и связана бесполезность разработанного приложения. Дело в том, что приложение мое использует упомянутые небезопасные операции. И чтобы мидлет при каждой такой операции не запрашивал разрешения пользователя, требуется подписать мидлет по-настоящему. Что это такое и почему это нереально рассказывается здесь.

пятница, 27 ноября 2009 г.

GIMP и скриншоты рабочего стола

Оказывается, весьма удобно делать скриншоты определенных частей рабочего стола с помощью GIMP.
File -> Create -> Screenshot (в старых версиях File -> Acquire -> Screeshot) ну и далее всё понятно...

[Upd] довольно странно, что фичу снимка выделяемой части рабочего стола я нашел только на линуксовой версии (генту), на винде возможно лишь заснять либо рабочий стол целиком, либо отдельное окно.

вторник, 24 ноября 2009 г.

Struts 2 tags

Из-за одной мелкой, примитивной задачи, чуть не пришлось добавлять очередную либу - JSTL. Задача заключалась в сохранении средствами тагов некоторой переменной, имеющей захардкоданое значение константы, в контекст страницы для последующего использования.
Попытка использовать struts 2 вариант

<s:set var="my_var" value="my_value"/>

ни к чему не приводила. Стратс искал объект с именем my_value.
Уже после того как добавил либу JSTL, обнаружил-таки правильный способ сделать это стратсовыми тагами. Делается с использованием OGNL escape sequence (%{expression}):

<s:set name="my_var" value="%{'my_value'}" />

В дальнейшем для получения значения переменной следует использовать опять OGNL escape sequence:

<s:property value="%{#attr.my_var}"/>

#attr - означает искать по всем скопам начиная со страницы, далее реквеста, далее сессии и наконец аппликейшна.
Для того, чтобы использовать значение переменной в выражении, например, для булевого условия, пишем:

<s:if test="%{#attr.my_var != 'my_value'}">
something strange!
</s:if>



воскресенье, 15 ноября 2009 г.

TestNG > JUnit

Достаточно странным может показаться то, что при всём внимании, уделяемом JUnit, за кулисами остается куда более мощный фреймворк - TestNG. Например, я узнал о нем совершенно случайно, когда попытался найти ответ - как же протестировать метод в условиях многопоточности средствами JUnit. Оказалось, что жюнит на этот вопрос отвечает молчанием, а тестнг предоставляет весьма удобный способ. Да и вообще, юзайте тестнг =).
Вот здесь небольшая статья-сравнение двух фреймворков с последующим выводом:

After go thought all the features comparison, i suggest to use TestNG as core unit test framework for Java project, because TestNG is more advance in parameterize testing, dependency testing and suite testing (Grouping concept). TestNG is meant for high-level testing and complex integration test. Its flexibility is especially useful with large test suites. In addition, TestNG also cover the entire core JUnit4 functionality. It’s just no reason for me to use JUnit anymore.

суббота, 14 ноября 2009 г.

Tomcat многострадальный

Когда удалось настроить Jmeter руки так и зачесались поиздеваться над томкатычем. он уменя 5.5.25. Итак, вот что получилось.
Я создал небольшое приложение на основе JPA, в котором с помощью запроса выбирал из БД MySQL 40 тыщ записей, в коде проходился по всем полученым ентити, считая среднее по одному параметру. Одинокий запрос, кинутый в томката, приходил ответом примерно через 1.4-2 секунды.

Томкат, запущенный с дефолтными параметрами виртуальной машины сдался после пары минут агонии все от 5 одновременных настойчивых потоков-клиентов. Что естественно, был выкинут эксепшын OutOfMemory. Кроме того, стоит отметить, что производительность томката (кол-во обрабатываемых запросов в секунду) падала с увеличением кол-во потоков.

Задав для томката аргумент -Xmx512m, я получил весьма устойчивого бойца. Горячая ночь с 50 одновременно ломящимися потоками не смогла его сломить. Из 65000 обработанных запросов было отвергнуто только 6. А производительность была выше, чем в случае одного потока. Позднее я попробовал в течение небольшого промежутка времени даже 100 одновременных потоков. Все прошло без проблем.

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

Достаточно интересным оказалось наблюдение за количеством занимаемой томкатом памяти. В течение теста она держалась на максимуме, что весьма ожидаемо. Однако, после окончания теста сборщик мусора даже в течение нескольких часов не удосужился освободить память, оставляя все как есть до худших времен. Вот такой вот лейзи сборщик. JDK я использовал сановскую, 1.5.0_12. Не могу конкретно оценить насколько такое поведение сборщика ухудшило бы производительность в реальных условиях, однако момент весьма неприятный.

Чтобы удостовериться в том, что сборщик действительно ленится (может он просто не видит, что есть мусор?), я написал сервлет который напоминал сборщику о его прямых обязанностях:
System.gc();
Последовательные вызовы сервлета смогли уменьшить занимаемую томкатом память в метрах 512 -> 356 -> 312 -> ... -> 110. Но неужели следует это делать вручную?
Вот здеся рассказывается о тонкостях сборщика мусора, потом следует почитать.

пятница, 13 ноября 2009 г.

JMeter: Начало.

Итак, дошли руки до JMeter. Удалось попробовать базовую функциональность - закидывание определенного адреса реквестами.
Так как мой сервер (а в данном случае в его роли выступал многострадальный tomcat 5.5.25) располагался локально то пришлось проделать следующие действия:
  1. добавить в воркбенч non-test element -> HTTP Proxy server
  2. в этом прокси настроить прослушиваемый порт
  3. стартануть прокси
  4. в фаерфоксе настроить выполнение всех реквестов через локальную прокси. это выполняется во вкладке "Сеть". Кроме того следует убрать дефолтовые фильтры фаерфокса, которые не пускают запросы на локалхост через прокси.
  5. Вбиваем нужный урл, он летит через ЖМетр, тот его ловит, сохраняет.
  6. Добавляем в тест план Thread group. Это своего рода контейнер для тестов, аналог ЖЮнитовского ТестСьюта. Копируем сохраненный реквест в Thread Group. Изменяем по необходимости параметры реквеста.
  7. Устанавливаем параметры Thread Group. Ramp-up period - период "разогрева". Время за которое стартанут все потоки. Стартуют они равномерно, так что если период 100 сек а потоков 10, то каждую 10ю секу будет стартовать поток пока их не станет 10. Loop count - кол-во запросов, которые каждый поток кинет. Лупы одного потока независимы от лупов других. Так что следует быть внимательным при настройке комбинации периода разогрева и кол-ва лупов, потому как можно придти к тому, что каждый добавляемый поток будет успевать откидать свои реквесты ранее, чем стартанет его коллега.
  8. Что ВАЖНО, никаких результатов мы не увидим, если не добавим листенера(ов). Листенера можно добавлять как для отдельных тестов так и для всего Thread Group. Я использовал Summary Report и Graph Results.
  9. Стартуем тест Run -> Start.
Что на данный момент не понравилось:
  • ограниченность графика в Graph Results, после заполнения всего отведенного места, график начинает начинает с самого начала, рисуя поверх себя.
  • я не нашел способа сохранить целый график, сохраняется лишь какая-то часть в зависимости от положения полоски прокрутки =(
  • при остановке теста (если был выбран вариант бесконечного выполнения либо если вы переоценили скорость своего сервера при нагрузке =) ) ЖМетр трактует все выполняющиеся на данный момент реквесты как неудачно выполненные серваком, что в итоге портит окончательный процент отвергнутых сервером запросов.
Возможно все перечисленные моменты вызываны тем, что я просто не нашел, как они устраняются.
Также отмечу, что при сохранении результата Summary Report в формате csv вы получите более точные значения.

первая тестовая запись через scribefire

тест, тест...
немножко шрифта, такого и такого
побольше можно попытаться
¢¤¦¨ª¬°
картинка требует фтп, настроим-с позже