63 заметки с тегом

prog

Коммит миграций кусками с помощью psql

Я ещё не так давно работаю с «Постгресом» и раз в месяц натыкаюсь на что-то неожиданное.

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

В «Оракле» такую миграцию наши ребята, насколько я знаю, разбивали хранимой процедурой на части и коммитили внутри кусками по миллиону, в «Постгресе» так нельзя — блок на языке PL/pgSQL выполняется в собственной транзакции и она прервётся при попытке сделать COMMIT. Автономных транзакций нет.

Испытания на тестовом стенде, приближенном к промышленному, показали, что единым куском обновить не получится — на мастере и слейве первой очереди кончилось место и стенд развалился. Надо было найти какой-то эквивалент сбросу миграции в цикле, по типу того как это делается в «Оракле».

Гугление рецептов принесло способ, который заключается в том, что мы создаём соединение из базы в в себя же и шлём запросы в это соединение. Говорят работает, но способ мне показался муторным, пришлось придумать свой.

DO $$
  DECLARE
    max_id table.id % TYPE;
    query TEXT;
BEGIN
  -- делим таблицу на куски по миллиону, теперь в max_id у нас номер последнего куска
  SELECT CEIL(MAX(id)::float/1000000) INTO max_id FROM mytable;

  -- очищаем файл /tmp/sqlquery
  COPY (SELECT '') TO '/tmp/sqlquery';

  -- айдишники в моём конкретном случае идут с единицы, но более правильно идти с минимума до максимума с шагом
  FOR i IN 0..max_id LOOP
        query = FORMAT(
            'UPDATE mytable '
            'SET something=value '
            'WHERE id BETWEEN ' || i*1000000+1 || ' AND ' || (i+1)*1000000 || ';'
        );

        -- запуск /bin/cat нужен, чтобы дописывать в файл
        EXECUTE  'COPY (SELECT ' || quote_literal(query) || ') TO PROGRAM ''/bin/cat >> /tmp/sqlquery''';
  END LOOP;
END$$;

-- запуск запроса
\i /tmp/sqlquery

Я воспользовался тем, что в накатке миграции у нас участвует утилита psql — официальный консольный клиент к «Постгресу», помимо команд СУБД она умеет выполнять свои собственные команды, чем я и пользуюсь — собираю нужные запросы в файл и запускаю его на выполнение в последней строке.

Обратите внимание на вызов /bin/cat — это важно, так как команда COPY сама не умеет добавлять что-то в файл, она его перезаписывает.

Трюк с прозрачностью

Ещё интересный трюк с прозрачностью — изменение картинки при наведении на неё мышкой. Трюк в том, что у картинки есть прозрачные области, а при наведении на неё мышкой, у контейнера, где находится картинка, меняется фон. Этот эффект можно использовать для подсвечивания пунктов меню, например, но, впрочем, не буду ограничивать вашу фантазию.

Эффекты для шрифта

Интересная техника изменения шрифта — наложить поверх текста полупрозрачную картинку, что даёт

ОЧЕНЬ ИНТЕРЕСНЫЕ ЭФФЕКТЫ.


Причём, такой текст индексируется поисковиками, его можно выделить и скопировать, а возможности его оформления почти безграничны и включают в себя даже анимацию, что может дать интересные эффекты, если применять эту возможность с умом.

TYPE=RANGE

Оказывается, в HTML 3.0 должен был войти тег INPUT TYPE=RANGE, но его, по каким-то причинам, не включили в HTML 3.2, который стали поддерживать браузеры. Но тег поддерживается современными браузерами Opera и Safari, насколько я понимаю, как часть стандарта WebForms. FireFox даже последних версий (не говоря уже об IE) этот тег не понимает.

Использование VRAM

Интересную статью обнаружил на просторах сети: «VRAM Storage Device — How to use the memory on GFX board in a different way». В статье показано как использовать лишнюю видеопамять под swap или как RAM-диск — я, буквально вчера, видел на Linux-сервере без GUI видеокарту с памятью 256Мб.

В статье показано как «откусить» у видеокарты память, которую она всё равно не использует. Я, для интереса, попробовал на нашем development-сервере (стоит S3 ViRGE/DX, 2Mb) откусить половину видеопамяти, по результатам опытов появилась несколько рекомендаций.

Во-первых, нельзя огульно верить всему, что написано в lscpi (см. статью). Если в результатах вывода написано о наличии региона некого размера, это ещё не значит, что на видеокарте именно столько памяти. Лучше посмотреть в лог X Window. Пример:

[root@hulk ~]# lspci -vv
...
02:01.0 VGA compatible controller: S3 Inc. ViRGE/DX or /GX (rev 01) (prog-if 00 [VGA])
        Subsystem: S3 Inc. ViRGE/DX
        ...
        Region 0: Memory at f4000000 (32-bit, non-prefetchable) [size=64M]
...
[root@hulk ~]# grep -i videoram /var/log/Xorg.0.log  
(--) S3VIRGE(0): videoram:  2048k

Во-вторых, лучше сделать modprobe и для остальных модулей, необходимых MTD для работы: mtdcore, mtdchar, mtdblock. Без этого, у нас на сервере, получить доступ к созданному устройству не получилось.

В остальном, всё работает замечательно:

[root@hulk ~]# cat /proc/swaps 
Filename                                Type            Size    Used    Priority
/dev/sda2                               partition       2096472 0       -1
/dev/mtdblock0                          partition       1016    0       0
2006   linux   prog

Как проверить ИНН

Как известно, у ИНН есть вполне определённая закономерность построения, в конце есть контрольная сумма, по которой можно проверить — правильно был введён ИНН или нет. В интернете алгоритм легко найти. К сожалению, номер паспорта на правильность ввода не проверишь, но, что интересно, и в этих цифрах зашифрована информация.

Если кратко, то первые две цифры — это код региона (у меня 92 — код Татарстана), следующие две цифры — год выпуска бланка паспорта (у меня 03 — 2003-й год, но паспорт выдан в конце 2002 года), остальные цифры — просто порядковый номер. Номер свозной (т. е. если в год закончился на номере 003500, то в следующем году первый номер будет 003501), начинается с 101 и заканчивается цифрами 999999, при переполнении нумерация начинается с номера 101.

Из этого правила есть исключение — 1997 г. в связи с какими-то причинами были выпущены паспорта́ специального тиража, к ним эти правила не применимы.

2006   prog

Как узнать есть ли шрифт

Очень оригинальный JavaScript нашёлся на просторах интернета — JavaScript font detection, т. е. скрипт, который обнаруживает — есть ли у пользователя определённый шрифт или нет.

Принцип прост — скрипт проверяет не является ли имя шрифта, которое запрашивается, шрифтом по-умолчанию. Если является, то сообщается, что шрифт есть, если нет, то запрашиваемым скриптом пишется фраза, а потом её получившийся размер (точнее размер охватывающего контейнера) сравнивается с той же фразой, написанной шрифтом по-умолчанию.

Если размеры совпадают, значит шрифта нет.

Разделяемая память

Удивительная вещь — до появления memcached никто, как будто бы, и не знал о существовании разделяемой памяти. Сейчас memcached почему-то называют лучшим решением. Это не так — у этого решения есть особенности, которые в некоторых проектах делают его не лучшим выбором. Memcached хорош двумя вещами — он позволяет держать данные в едином хранилище (например, несколько frontend делят общий кеш) и объединять несколько серверов (масштабируемость). Другие его особенности делают его выбор в некоторых проектах нерациональным (в других — напротив, лучшим решением), а именно: отсутствие блокировок (нельзя заблокировать какой-то ключ, прочитать, вычислить новое значение, разблокировать) и работа через TCP/IP.

Кроме того, у memcached есть особенность, которую тоже надо учитывать. Есть случаи, когда memcached может удалить данные из кеша, вот комментарий разработчика Анатолия Воробья:

Есть набор классов по величине памяти — например, в самом простом и дефолтном варианте, есть класс размером в 128 байт, потом 256 байт, потом 512, 1k, 2k итд. до 1Mb. Если какая-то запись (ключ+значение+ дополнительные заголовки) занимает, скажем, 1.5k, под нее отводится кусок из класса в 2k, т. е. кусок размером в 2k, и она в него пишется.

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

Ссылки на другие способы доступа к разделяемой памяти есть в аннотации к модулю PEAR System::SharedMemory.

2006   memcached   php   prog

Скорость замены в PHP

Провёл небольшие замеры в PHP. Задача следующая — заменить вхождения между двумя ограничителями (в моём случае — фигурные скобки) по хешу, где ключём хеша является значение, которое заменяем, значением хеша — то, на что заменяем. Сделал несколько реализаций, с использованием различный функций (слева функция, справа — время в секундах замены из одного и того же словаря на приличного размера тексте):

strpos — 0.23691987991333
explode — 0.27920699119568
preg_replace_callback — 0.34914493560791
str_replace — 1.8960340023041
strtr — 3.1935269832611

Во многом результаты довольно ожидаемые, но кое-что удивило — скорость замены через str_replace и strtr сильно различается, а explode (разбиение по первому ограничителю, потом, что осталось — по второму) почему-то оказался почти таким же быстрым, как и strpos (поиск первого ограничителя, потом второго).

2006   php   prog

MHTML

В предыдущей статье я описывал способ для Internet Explorer, позволяющий внедрить картинки в HTML-код. К сожалению, у него нашёлся недостаток — файл, в котором содержатся ресурсы, должен иметь расширение «mht». Иначе в некоторых версиях Windows браузер ничего не покажет.

Если подумать, это не сильно меняет дело — всего-то придётся выделить «упаковку» картинок в отдельный файл и подключать по мере необходимости. Например, так:

<img src="mhtml:http://sample.com/package1.mht!image.jpg" />
<img src="mhtml:http://sample.com/package1.mht!another_image.gif" />

и так далее. Основное достоинство способа — объединение нескольких картинок в одном соединении и его удаётся сохранить.

Сегодня я расскажу как добиться мультибраузерности при помощи SSI. В других скриптовых языках такой проблемы, понятно, не возникает. Я буду рассматривать SSI веб-сервера Apache, для других серверов, думаю, адаптировать код можно будет без особых проблем. Странно, SSI, этот простой и быстрый язык, который часто отлично подходит для организации нагруженных сайтов, где хотелось бы держать информацию структурированно, почему-то считают недостаточным для программирования. Тем не менее, на нём можно делать достаточно сложные вещи (я как-то писал «песню про пиво» на этом языке, загляните в раздел «99»).

Символом «собачки» (@) я буду выделять места, где перевод строки не нужно ставить — просто мне приходится разбивать длинные места на части. Описание, если не интересно, можно и не читать, просто скопировать всё в нужный файл и положить в каталог /images/.

В настройках Apache или .htaccess должна быть включена обработка SSI в файлах .html и .mht:

AddHandler server-parsed .html .mht

Первый файл (или файлы), который понадобится — это файл самой картинки. Он должен начинаться с полного имени картинки, плюс расширение .html. Например, «1.jpg.html», внутри нужно указать MIME-тип картинки в переменной «TYPE» и после include пометить код картинки в base64:

<!--#set var="NAME" value="$QUERY_STRING" -->@
<!--#set var="TYPE" value="image/jpeg" -->@
<!--#include virtual="pict.html" -->@
4AAQSkZJRgABAgAAZABkAAD...код картинки...mJiBFoxCGkShUxyGCMYMRcSwwRiMdRZ

Следующий файл — img.html. В нём проверяется из какого браузера его вызывают — Internet Explorer или всех остальных (вторым условием убирается Opera, которая иногда притворяется IE) и, в зависимости от этого, выводит, либо ссылку на mht-файл (у меня в коде считается, что все эти файлы лежат в каталоге /images), либо data URL, который генерирует pict.html:

<!--#if expr="$HTTP_USER_AGENT=/MSIE/ && $HTTP_USER_AGENT!=/Opera/" -->@
mhtml:http://<!--#echo var="HTTP_HOST" -->/images/package1.mht!<!--#echo var="QUERY_STRING" -->@
<!--#else -->@
<!--#include virtual="$QUERY_STRING.html?$QUERY_STRING" -->@
<!--#endif -->

Внутри файла package1.mht ссылки на файлы картинок (обратите внимание на параметры вызова в include virtual), в константе BOUND задаётся boundary (разделительная строка), о которой я говорил в прошлый раз. В include надо перечислить (пример показан для двух файлов) все файлы картинок, которые будут входить в этот набор.

<!--#set var="BOUND" value="Next_Section" --><!--
MIME-Version: 1.0
Content-Type: multipart/related; boundary="<!--#echo var="BOUND" -->"

--<!--#echo var="BOUND" -->
Content-Location: index.htm
Content-Transfer-Encoding: base64
Content-Type: text/html

<!--#set var="MHT" value="1" -->
<!--#include virtual="1.jpg.html?1.jpg" -->
<!--#include virtual="2.jpg.html?2.jpg" -->

--<!--#echo var="BOUND" -->-->

Последний файл — pict.html. Вызывается он из файлов картинок. Если он вызывается из mht, то выдаёт кусок mht-кода для данной картинки, иначе — data URI.

<!--#if expr="$MHT" -->--<!--#echo var="BOUND" -->
Content-Location: <!--#echo var="NAME" -->
Content-Transfer-Encoding: base64
Content-Type: <!--#echo var="TYPE" -->

<!--#else -->data://<!--#echo var="TYPE" -->;base64,<!--#endif -->

Теперь, как применять эту груду файлов. Всё очень просто — просто вставляем в нужно место следующий тег:

<img src="<!--#include virtual="/images/img.html?2.jpg" -->" />

И смотрим на результат. В исходном коде в IE мы должны увидеть ссылку на package1.mht, в остальных браузерах — data URI, во всех браузерах — картинку.

Ранее Ctrl + ↓