среда, 28 ноября 2012 г.

INSERT ... ON DUPLICATE KEY UPDATE deadlock

А вот какие грабли можно получить, если делать множественный INSERT (где перечисляются несколько рядов разом через VALUES) ON DUPLICATE KEY UPDATE.

Случай несколько специфичен. Имеется баннерная система, выдает баннеры, например по 2 шт, при выдаче увеличивает счетчики показов для каждого баннера. Не забывает перемешивать баннеры shuffle-ом перед выдачей (делает это ДО подсчета показов).

При мало-мальски большой нагрузке (10rps) уже проскакивали дедлоки, пара штук в час примерно.
Делаем запрос show engine innodb status; смотрим секцию "LATEST DETECTED DEADLOCK"
Видим там две поссорившиеся транзакции:
*** (1) TRANSACTION:
TRANSACTION 26A4ED2EF, ACTIVE 0 sec inserting
mysql tables in use 1, locked 1
LOCK WAIT 3 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1
MySQL thread id 5361085, OS thread handle 0x7f6f31c76700, query id 71605993 blabla
INSERT INTO stat (`banner_id`,`dt`,`views`) VALUES (1283, CURDATE(), 1), (1282, CURDATE(), 1) ON DUPLICATE KEY UPDATE views = views + 1
*** (1) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1079 page no 358 n bits 376 index `main_key` of table blabla trx id 26A4ED2EF lock_mode X locks rec but not gap waiting
*** (2) TRANSACTION:
TRANSACTION 26A4ED2F0, ACTIVE 0 sec inserting, thread declared inside InnoDB 497
mysql tables in use 1, locked 1
3 lock struct(s), heap size 1248, 2 row lock(s), undo log entries 1
MySQL thread id 5360789, OS thread handle 0x7f6f0fc30700, query id 71605995 blabla
INSERT INTO stat (`banner_id`,`dt`,`views`) VALUES (1282, CURDATE(), 1), (1283, CURDATE(), 1) ON DUPLICATE KEY UPDATE views = views + 1
*** (2) HOLDS THE LOCK(S):
RECORD LOCKS space id 1079 page no 358 n bits 376 index `main_key` of table bla trx id 26A4ED2F0 lock_mode X locks rec but not gap
*** (2) WAITING FOR THIS LOCK TO BE GRANTED:
RECORD LOCKS space id 1079 page no 358 n bits 376 index `main_key` of table bla trx id 26A4ED2F0 lock_mode X locks rec but not gap waiting
*** WE ROLL BACK TRANSACTION (2)
в итоге вторую mysql откатил.
вспоминаем, что banner_id и dt - уникальный ключ, обращаем внимание, что в обоих запросах обновляется по 2 ряда, причем в первом запросе сначала идет баннер 1283 потом 1282. Во втором же запросе сначала баннер 1282 потом 1283.
Вспоминаем про shuffle ДО подсчета показов. При желании материмся. Делаем выводы.

Выхода два: можно подсчитывать показы ДО shuffle, а можно делать отдельные запросы на подсчет для каждого баннера (по-моему так надежнее).

суббота, 20 октября 2012 г.

Обнаружение и разруливание коллизий в сети на протоколе UART

Я долго думал над проблемой объединения кучи микроконтроллеров (МК AVR) в общую сеть. Хотелось иметь простой протокол, в идеале - UART. Но он во-первых не умеет разруливать коллизии, и во-вторых вообще-то даже не предусматривает присутствие нескольких устройств на общей шине!
Но нас такими глупостями не испугаешь.
Поскольку UART мне был нужен также "для самых маленьких" МК (вплоть до tiny13), его пришлось программить самому. Ну а раз пишем сами, то и правила устанавливаем свои :)

Описать сеть я мог бы так: один ПК, много МК на общей шине, полный дуплекс, т.е. отдельные линии RxD и TxD, ПК рассылает на всех разом, МК могут инициировать связь с ПК (но не друг с другом). Схема будет под катом.

В итоге был реализован немного расширенный UART-протокол общения с ПК, который вообще-то полностью совместим с generic-UART, имеет обнаружение коллизий, режим пакетной передачи и позволяет иметь на линии сколь угодно много МК, каждый из которых совершенно свободно может передавать данные в сеть, как только пожелает.
Особенности: никаких арбитров, маркеров, "ответов-только-если-спросили" и прочих ограничений. Абсолютная демократия!
То есть посылаешь в сеть широковещательное "Кто тут?!" и получаешь в ответ аккуратные пакеты, содержащие ответ с адресом каждого МК. Никакой каши.
В виде бонуса, каждому МК можно поставить 3 светика, которые будут отражать соответствующие системные флаги "Линия занята", "Коллизия" и "FRAME ERROR".

Как же я этого добился?!

понедельник, 15 октября 2012 г.

Пишем приложение для Android в Appcelerator (Titanium Studio)

Небольшой tutorial "как писать приложения под Android" от человека, который под телефоны никогда ничего не писал, Java не знает и вообще PHP-разработчик.

PHP-разработчики не всегда знают Java, зато они все должны знать JavaScript. Есть такая штука, Titanium Studio, позволяет писать мобильные приложения на JavaScript. Она еще и бесплатная. Какая удача!

четверг, 11 октября 2012 г.

Не работает CURLOPT_CONNECTTIMEOUT_MS

Очередной квест при работе с curl.
Нужны были таймауты в миллисекундах, версия libcurl 7.21, версия php 5.3, т.е. условиям соответствует.

Но не работает..

тестовый код
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, "http://192.168.0.1/");
curl_setopt($ch, CURLOPT_CONNECTTIMEOUT_MS, 300);
curl_setopt($ch, CURLOPT_VERBOSE, 1);
$res = curl_exec($ch);
var_dump($res, curl_error($ch));
выводит

* Closing connection #0
* Timeout was reached
bool(false)
string(19) "Timeout was reached"

Т.е. даже никаких тебе About to connect и Trying 192.168.0.1, сразу Closing connection, и хоть ты волком вой.
Пробовал переустанавливать libcurl, php5-curl, не помогло.
Полез в гугл по запросу "curlopt_connecttimeout_ms,  timeout was reached" и вышел на спасительный комментарий в мануале:
http://www.php.net/manual/ru/function.curl-setopt.php#104597
The problem is that on (Li|U)nix, when libcurl uses the standard name resolver, a SIGALRM is raised during name resolution which libcurl thinks is the timeout alarm.

т.е. если libcurl использует стандартный name resolver, в процессе резолвинга посылается сигнал SIGALRM, который libcurl принимает за таймаут!

Установка опции nosignal решила проблему.
curl_setopt($ch, CURLOPT_NOSIGNAL, 1);

SOLVED

среда, 3 октября 2012 г.

Интересное поведение mkdir в php

Внезапно обнаружилось, что mkdir не работает с указанием прав так, как от нее ожидается. По крайней мере при запуске скриптов из крона.
Пытаешься указать ей права 770 - папка создается как 750.
Пытаешься 777 - создается как 755. Явно просматривается ограничение по umask.
Но что интересно, chmod() на 770 говорит ОК, следом тут же проверка fileperms() говорит 770, НО по факту в ФС - 755! Ну нихрена себе, мир рушится! Как я теперь могу доверять PHP?!?

В итоге было выяснено, что пых работает с umask 0022.
Вызов umask(0002) перед файловыми операциями привел права в норму, но поведение chmod+fileperms все равно удивляет.

Значит надо запускать php-fpm с явным заданием umask 0002 например.
Однако в дефолтном /etc/bashrc было задано 0002. WTF?!?

Оказалось, что крон просто не цепляет bashrc!

среда, 26 сентября 2012 г.

Сколько ест компьютер

Сегодня скуки ради взял мультиметр, включил его в разрыв шнура питания БП компа и замерил ток. Давно меня интересовала эта цифра.

В биосе график был ровный, в районе 0.35A, во время загрузки - скакало от 0.35 до 0.45 ампер, после загрузки цифра вернулась к значению 0.30-0.32A.

Запустил Rad Alert 3, скоро кулеры взвыли, а ток вырос до 0.45-0.55A.

Замеры в ждущем режиме показали 0.03A.

ИТОГО: потребление системника в ждущем режиме - 6.5Вт, а при работе где то 60-120Вт.

Конфигурация:
* Intel SSD SA2M160G2GC
* Intel(R) Core(TM) i5 CPU 760 @ 2.80GHz
* 2x2Gb DDR3-1333
* Asus P7H55-M/USB3
* Простенькое Видео HD6670

Самое главное забыл, БП какой то RealPower CG-400W (400Вт).

UPD: померял ваттметром, 70..80..90..100 при загрузке, около 80 в режиме простоя, 135 в режиме игры, 5 в ждущем.
Ваттметр такой

вторник, 25 сентября 2012 г.

FastCGI "Primary script unknown"

Столкнулся сегодня с сабжевой проблемой, косяк произошел после обновления nginx с 0.7.67 на 1.2.3.
Сайты стали отдаваться с ошибкой 404 и текстом "File not found". Что интересно, не все сайты.. Некоторые работали.
Долго бил во всяческие бубны, поднимал php-cgi на локальном порту вместо php-fpm через сокет, права проверял, конфиги пересмотрел раз 10, включал логи php-fpm, nginx-а. Вырисовывалось, что работают сайты, которые не используют ЧПУ (у них ссылки ведут на реальные скрипты, старые совсем сайтики).

ЧПУ сайтов у меня основано на обработке 404й ошибки и подмене SCRIPT_FILENAME на конкретный файл MVC-контроллера.

В итоге собака была зарыта в include fastcgi_params;
Раньше эта строка стояла под определением SCRIPT_FILENAME, и как то это работало, несмотря на то, что include fastcgi_params шло ниже и по идее должно было переопределять SCRIPT_FILENAME. После обновления же nginx видимо поменялось поведение.
Была мысль, что обновленный nginx и файл fastcgi_params обновил, однако время изменения файла было далеко в прошлом.

В общем проблема решилась установлением строки include fastcgi_params; на первое место во всех секциях по обработке php.

четверг, 23 августа 2012 г.

Basic authorization logout

Как разлогиниться, если используешь Basic-авторизацию или, по-другому, HTTP-авторизацию?
Как оказалось не так уж просто, но все же возможно, причем вся логика - на серверной стороне, а значит метод кроссбраузерный!

Все что потребуется - контролировать пару флагов в сессии.
Суть в том, что если юзер авторизован - в сессии хранится его ID, а раз уж ID есть, то и пароль с логином спрашивать ни к чему. Однако есть и другой флаг, назовем его reauth, который показывает, что мы затребовали выход из системы.
При взведении этого флага сессия юзера очищается, а логин-пароль принудительно прячутся (т.е. метод getEnvLoginPasswd() просто говорит "а нету, пытай меня сволочь немецкая!"), это важно, иначе чуда не произойдет.

пятница, 29 июня 2012 г.

Комментарии в named.conf

Сегодня обнаружил косяк при настройке зоны в BIND.
Занес я новую зону, используя воспеваемый всеми ламерами webmin, но вот в списке ее не увидел. Полез в named.conf, зона прописана, от остальных ничем не отличается.. разве что расположена ниже одного закомментированного блока.

Блок был закомментирован как я люблю:
/* если надо раскомментить, удаляем этот пробел -> * /
blablabla
/* */
Любопытно, после удаления блока в интерфейсе появились все зоны, которые были прописаны ниже него.

Как я AT командами телефона шатал. Часть 2


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

Немного о том, что же делать дальше.
А дальше надо как то раскодировать все то, что было получено с телефона, программно (на PHP в моем случае). Не вручную же сидеть переводить с кодовыми табличками.


Получив какую-нибудь входящую (!!, важно) смс-ку в PDU формате из телефона, начинаем ее разбирать по мануалу (для исходящей другой алгоритм разбора). Например (пробелы расставил для наглядности)
07919762020082F8 44 14 D03C5EB37C0E1BDF6E9F0F 00 08 21505291421061 8C 050003360601042D0422041E002004120410042800200053004D0053002D041A0423041F041E041D0020041D041000200421041A04180414041A0423002100200422043E043B044C043A043E0020044104350433043E0434043D044F0020043F043E04370432043E043B044F043504420020043F043E0434043A043B044E044704380442044C002004110415

Начинаем читать. 

пятница, 1 июня 2012 г.

Подключение пьезодинамика (buzzer) к МК AVR

Сегодня потратил часок времени на проблему подключения пищалки от компьютера к МК AVR. Суть проблемы - практически неслышное пищание даже на расстоянии 10см. Я перепробовал разные методы: и обычное включение "нога-buzzer-земля", и подключение к 2 ногам с попеременной подачей на них 01 и 10, и подключение через транзистор разными способами. Все равно пищало тихо.

В итоге проблема была в излишне частом дрыгании ногами. МК у меня работал на частоте 8МГц, а между установкой и снятием напряжения с ноги я ставил всего 10-15 NOP-ов..
Когда я написал простую функцию задержки на 0xFF циклов и таким образом сильно снизил частоту ШИМ, динамик звонко запищал!

Получившийся код ниже

cmd_beep:
push temp
ldi temp, 0x01 ; длительность писка
  cmd_beep_loop:
  dec temp
push temp
ldi temp, 0xFF
  cmd_beep_loop2:
    SBI BUZZER_PORT, BUZZER_PIN
rcall delay
    CBI  BUZZER _PORT, BUZZER_PIN
rcall delay
  dec temp
cpi temp, 0x00
brne cmd_beep_loop2
pop temp
cpi temp, 0x00
brne cmd_beep_loop
pop temp
ret

delay:
push temp
ldi temp, 0xFF
  delay_loop:
  dec temp
cpi temp, 0x00
brne delay_loop
pop temp
ret

Проблемы вывода CP1251 в терминале UTF-8

Если вам приходится работать с svn-проектами в кодировке cp1251, имея системную локаль UTF-8, возможно вы сталкивались с трудностью отображения кириллицы cp1251 в консоли UTF-8 при выполнении svn diff.

Решение простое - запустить новую копию терминала с другой локалью.
> LANG=ru_RU.cp1251 gnome-terminal
и в нем уже работать с svn
теперь кириллица выводится

воскресенье, 13 мая 2012 г.

Как я AT командами телефона шатал

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

Проблемы начались сразу же. Подключил телефон, а он - ноль эмоций, батарея такая древняя, что кажется уже разлагается. Меряю напряжение - 1.6В (батарея 3.6В), ладно, оставляю заряжаться, через минут 10 экран оживает и демонстрирует сиське индикатор заряда! Отлично!
Не так отлично, как если бы телефон умел работать без батареи от одного только дата-кабеля, но хотя бы так.

Включаю!

Старичок загрузился, ставлю дрова на кабель, появился новый ком-порт, расчехляю программу Terminal, коннекчусь, лихорадочно набираю AT<Enter> и, конечно, получаю отлуп (а иначе сказки-то и не было бы).. т.е. вообще ничего, тишина.

среда, 4 апреля 2012 г.

Как грабить видео с rutube из PHP

В отличие от YouTube, где видео грабится довольно просто, на RuTube используется rtmp.
И вот этот самый rtmp съел мне весь мозг, т.е. я вообще то знаю как грабить rtmp поток, но в этом случае все оказалось несколько сложнее.
Обычно для граббинга rtmp используется команда примерно такого вида (пример уже для ролика на rutube, может и не работать уже, ибо ссылки походу протухают)
rtmpdump -r rtmp://video-13-17.rutube.ru/rutube_vod_1 -W "http://rutube.ru/player.swf?file=http://bl.rutube.ru/79739a3e8ff8023db07dfe1f2d50edc6.iflv" -y "mp4:vol32/movies/79/73/79739a3e8ff8023db07dfe1f2d50edc6.mp4?e=1333442242&s=55c404be47f98c43d26df9a845ae8aca"  --timeout=4 -o out.mp4 [--resume]
возможные ошибки:
 - никаких &amp; в командной строке, только &
 - если выполнять из консоли linux, параметры, содержащие амперсанд (&) нужно взять в кавычки (как в примере выше)

гемор:
 - рутуб выдает с ограниченной скоростью, rtmpdump выкачивает с максимальной скоростью, и когда буфер достигает 1.5Мб (второй догоняет первого) - случается коллапс.. рассуждая так, я пробовал искуственно ограничить скорость выкачки, получилось примерно следующее
$cmd = 'rtmpdump -r rtmp://video-13-17.rutube.ru/rutube_vod_1 -W "http://rutube.ru/player.swf?file=http://bl.rutube.ru/79739a3e8ff8023db07dfe1f2d50edc6.iflv" -y "mp4:vol32/movies/79/73/79739a3e8ff8023db07dfe1f2d50edc6.mp4?e=1333442242&s=55c404be47f98c43d26df9a845ae8aca"  --timeout=4';
$size = 0;
if (!($fp = popen($cmd_tpl, 'r'))) {
    echo 'cant open cmd pipe' . "\n";
    die;
}
while ($bytes = fread($fp, 1024)) {
    usleep(50000); // try to grab in realtime 10sec video in real 10 seconds
    $size += strlen($bytes);
    echo '.' . $size;
    //fwrite($wf, $bytes); // запись в целевой файл, здесь не представлен
}
качалось медленно, чего и добивался, однако не помогло) при (долгой) закачке первых же 1.5Мб кэша - обрыв
пришлось пойти другим путем - использовать параметр --resume команды rtmpdump

exec($cmd_tpl, $out, $ret);
$cycles = 100; // защита от бесконечности
while ($ret !== 0 and $cycles-- > 0) {
    exec($cmd_tpl . ' --resume', $out, $ret);
}
if ($ret !== 0 and $cycles <= 0) {
    echo 'Failed to grab' . "\n";
    die;
}
echo 'Successfully grabbed ' . "\n";
в несколько подходов, довольно долго, но все же в итоге мы сохранили видео с rutube! на выходе - flv-видеофайл! Параметр timeout рекомендую поставить  от  2 до 4 сек
enjoy

upd: видимо у меня была несколько косячная версия rtmpdump (из репов), последняя 2.4 из git://git.ffmpeg.org/rtmpdump качает без разрывов

воскресенье, 25 марта 2012 г.

Прошивка телефона Samsung S8500 на bada 2.0 вручную

Сегодня наконец дошли руки проверить, не вышла ли уже наконец эта Bada 2.0. И я возрадовался - таки вышла! Однако как всегда, все оказалось не так радужно, как хотелось бы. Через Kies 2.2 обновление не происходило, т.е. после скачивания прошивки мне просто было сообщено, что обновление не удалось.. и кнопка "Подтвердить".. ну подтверждаю, хуле..

немного порывшись в инете, нашел инструкцию по прошивке. Саму прошивку на соответствующий телефон можно найти здесь http://badablog.ru/programmnoe-obespechenie-proshivki-dlya-smartfonov-samsung-wave/ , а инструкция как правильно все сделать - здесь http://badablog.ru/forum/viewtopic.php?f=38&t=1502

Поставил S8500XXKK5, по инструкции, все прошло нормально, разве что COM4 после запуска процесса показал ошибку, и обнаружился COM6, я выбрал его и попробовал запустить прошивку снова.. на этот раз все пошло-поехало.


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

upd: нашел другую, S8500XXLA1_S8500OXFLA2_SEB, с поддержкой русского. Скачать прошивку S8500XXLA1_S8500OXFLA2

суббота, 3 марта 2012 г.

запилил, наконец-таки, подсветку в сортире
видео тут http://www.youtube.com/watch?v=tvTCrlGoN6I

итого теперь с мобилки можно включить свет на кухне и подсветку в сортире! офигенно, скоро можно будет, не вставая с толчка, поставить чай

выполнение ssh команд из php без запроса пароля

когда возникает необходимость ssh взаимодействия между двумя машинами, создаются ключи доступа, например командами
ssh-keygen -t rsa
ssh-copy-id user@host
и все хорошо.. однако случись что с ключами, и exec('ssh ...') в php-скрипте затребует пароль, вероятно повесив скрипт надолго..

из ошибки
Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password)
можно догадаться, что софтина перебрала все перечисленные способы и войти не удалось, последняя надежда - спросить пароль у юзера.. вот это и хотелось бы отключить
чтобы софтина не задавала глупых вопросов, можно заюзать опцию
-o PasswordAuthentication="no"
все вышеописанное специально для тех, кто не любит мануалы

суббота, 18 февраля 2012 г.

настройка /dev/ttyUSB0 в raw режим

как то однажды на переустановленном линухе мое устройство на ATTiny24 отказалось общаться с компом через конвертер USB-COM на базе микрухи FT232RL. Проверив в программе Terminal из под windows, я убедился, что само устройство в порядке, значит дело в настройке порта под никсами. Смотрим, что там на данный момент
stty -F /dev/ttyUSB0
speed 9600 baud; line = 0;
min = 1; time = 0;
-brkint -icrnl -imaxbel
-opost -onlcr
-isig -icanon -iexten -echo -echoe -echok -echoctl -echoke

скорость подходящая, значит не хватает каких то опций. ответ искать пришлось недолго.

итак, настройка виртуального com-порта  под linux (обычно определяется как /dev/ttyUSB0) в raw-режим:
stty -F /dev/ttyUSB0 cs8 9600 ignbrk -brkint -imaxbel -opost -onlcr -isig -icanon -iexten -echo -echoe -echok -echoctl -echoke noflsh -ixon -crtscts
UPD: кстати о настройке таймаута чтения из COM-порта
параметр min задает число байт, после которого таймаут активируется, параметр time задает таймаут с шагом 100мс.
Итого, чтобы задать таймаут 1.5сек без оглядки на число принятых байт, делаем так:
stty -F /dev/ttyUSB0 min 0 time 15

среда, 11 января 2012 г.

Смотрим rtmp Online TV в XBMC

озадачился созданием списка онлайн каналов, да так, чтоб не на сайте смотреть, а иметь ссылки-источники на любой случай. хочешь VLC смотри, хочешь в XBMC пихай

в особо простых случаях смотрим исходник страницы, выдираем из ebmed url источника и проверяем его валидность, открывая в VLC

в случаях посложнее имеем rtmp (rtsp, rtmpe, etc..) поток, транслируемый flash-плеером на странице. просто так rtmp://url VLC плееру скормить не всегда удается, приходится изворачиваться. например используя прогу rtmpdump.