935 заметок с тегом

программирование

Позднее Ctrl + ↑

mozjpeg 3.3.1

Заворачивал в пакет для седьмой ЦентОСи относительно свежий mozjpeg. В теории всё просто, на практике просто так пакет не собрался, пришлось корректировать руками. Запишу себе сюда, чтобы не забыть что делал.

Нужно отредактировать в двух местах файл mozjpeg.spec.in (ниже готовый патч под утилиту patch):

diff -urd --ignore-blank-lines --minimal a/release/mozjpeg.spec.in b/release/mozjpeg.spec.in
--- a/release/mozjpeg.spec.in	2017-07-10 13:58:14.000000000 +0300
+++ b/release/mozjpeg.spec.in	2018-10-12 12:30:04.172828265 +0300
@@ -8,7 +8,7 @@
 %define _datadir %{__datadir}

 # Path under which docs should be installed
-%define _docdir /usr/share/doc/%{name}-%{version}
+%define _docdir /opt/mozjpeg/doc/%{name}-%{version}

 # Path under which headers should be installed
 %define _includedir %{__includedir}
@@ -35,7 +35,7 @@
 Release: @BUILD@
 License: BSD-style
 BuildRoot: %{_blddir}/%{name}-buildroot-%{version}-%{release}
-Prereq: /sbin/ldconfig
+Requires(pre,preun): /sbin/ldconfig
 %ifarch x86_64
 Provides: %{name} = %{version}-%{release}, @PACKAGE_NAME@ = %{version}-%{release}, libturbojpeg.so()(64bit)
 %else

Дальше запустить:

autoreconf -fiv
./configure
make rpm

И получится пакет.

Предложил авторам утилиты правку на «Гитхабе», посмотрим примут ли.

Дополнение: ура, патч приняли в репозиторий, теперь можно не патчить самостоятельно.

2018   jpeg   программирование

Мелочь в синтаксисе SELECT

В синтаксисе запроса SELECT «Постгреса» есть приятная мелочь, которая хоть и нестандартна, но греет мне душу, — согласно описанию, выбираемые поля (часть между SELECT и FROM) можно опускать.

Вот как это работает в консоли:

SELECT FROM usr;
--
(588910 строк)

Кстати, можно ещё поставить там ключевое слово ALL, будет результат будет точно такой же.

Для чего это может пригодиться? Для подзапросов с EXISTS. Мне не нравится, как выглядит всем привычный вариант:

SELECT COUNT(*)
FROM document
WHERE EXISTS (
    SELECT NULL
    FROM document_n
    WHERE id = document.id
)

В подзапросе после SELECT по стандарту надо что-то указать, всё равно что, использоваться это не будет. Мне такая избыточность не по вкусу. А вот «Постгрес» позволяет ничего там не указывать:

SELECT COUNT(*)
FROM document
WHERE EXISTS (
    SELECT
    FROM document_n
    WHERE id = document.id
)

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

Если когда-либо встанет вопрос о переезде на другую СУБД, то вышеописанное — самая малая из проблем и решить её просто — заменой через регулярное выражение.

2018   postgres   программирование

Примерная оценка в Постгресе

Читая документацию по «Постгресу», набрёл на интересную конструкцию — TABLESAMPLE. Она позволяет обработать запросом не всю таблицу, а только указанный процент, причём строки выбираются случайным образом.

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

SELECT id FROM (
    SELECT id FROM very_big_table TABLESAMPLE SYSTEM (.0001) LIMIT 100
) _ ORDER BY RANDOM() LIMIT 1

Тут выбирается одна десятитысячная процента таблицы (0,0001%), а потом из этой выборки берётся первая строка. На настоящей таблице с почти миллиардом строк, такой запрос у меня занял около ста миллисекунд.

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

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

Типа, сколько в среднем примерно сотрудники некой гипотетической компании тратят на обед в зависимости от пола (оценка по одному проценту данных):

SELECT sex, AVG(spent)
FROM meal TABLESAMPLE SYSTEM (1)
WHERE mtime BETWEEN SYMMETRIC '12:00:00' AND '14:00:00'
GROUP BY 1

Или сколько примерно раз я ездил такси «Везёт» за последние семь лет (оценка по пяти процентам и экстраполяция):

SELECT COUNT(*)*20
FROM taxi_call TABLESAMPLE BERNOULLI (5)
WHERE carrier='vezet' AND cdate >= '2011-08-03'
2018   postgres   программирование

Шило на мыло

Всё-таки я большой поклонник статической типизации в языках. Жаль, что ПХП она только-только начинает проникать.

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

<?php
$array = '';
$array[PHP_INT_MAX] = 1;

Главное тут в том, что массив почему-то проинициализирован как строка.

Несмотря на эту странность, всё работало — ПХП на втором присваивании преобразовывал строку в массив. А какое-то время назад этот код стал валиться с нехваткой памяти. Я сегодня разбирался с этой ошибкой.

Оказалось, что в ПХП 7.1 и выше (мы недавно перешли с 7.0 на 7.2), преобразование в массив тут больше не происходит. Зачем-то одно странное поведение заменили другим — теперь в этом коде создаётся гигантская строка, состоящая из пробелов и в позицию PHP_INT_MAX записывается символ «единица». Вот память и кончается. 🤦

2018   php   php7   программирование

Статический анализ в Go

С интересом попробовал в действии gocritic — статический анализатор для Гоу, статья о котором в прошлом месяце появилась на «Хабре». Он в самом начале пути, но кое-что уже умеет.

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

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

После успешного запуска получилось примерно два экрана замечаний, большей частью относящихся к устаревшим за время существования проекта практикам, но парочка замечаний была действительно полезна. Жаль, что пока нет интеграции с каким-либо редактором кода, как у прекрасного РеШарпера — он сам предлагает правку, остаётся только её принять.

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

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

Во-первых, в одном из циклов происходила итерация с копированием значения, цикл вызывается нередко, поэтому это заметное исправление.

rangeExprCopy: copy of utf (256 bytes) can be avoided with &utf

Во-вторых, в трёх местах анализатор посоветовал заменить «магические значения» на константы, которые оказывается (я не знал), есть в соответствующих модулях. Это полезно для читаемости кода и для самообучения — как результат я узнал что-то новое.

stdExpr: can replace "POST" with net/http.MethodPost

По моему мнению очень полезный проект, желаю ему дальнейшего развития!

2018   googlego   программирование

Падение libmemcached

С годами «Мемкешед» всё меньше кажется хорошим выбором в связке с ПХП. Всё время какие-то проблемы. Недавно столкнулись с очередной — при выставлении определённых опций распределения ключей на несколько серверов, модуль мемкешеда в ПХП иногда крашится вместе с интерпретатором.

Баг известный и проявляется на системах с libmemcached 1.0.16, а у нас ЦентОСь, там новее нету.

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

2018   memcached   php   программирование

Третий параметр define

ПХП неисчерпаем, как атом, — читал какую-то статью о развитии языка (ссылку потерял) и узнал, что у функции define есть третий, необязательный параметр. Столько лет программирую на ПХП и не знал!

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

А ещё define возвращает результат — успешна ли операция:

@var_dump(define("True", false, true)); // bool(false), будет конфликтовать со встроенной константой
var_dump(define("True", false)); // bool(true)

Кстати, вторая строка константу вроде успешно устанавливает, но на деле воспользоваться ей невозможно — булевые константы языка к регистру нечувствительны и видимо перекрывают пользовательские. Странно, что тут нет ошибки, ещё один камень в огород ПХП.

2018   php   программирование

Злой ПХП

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

var_dump(DateTime::createFromFormat("d.m.Y", "01.01.1970"));
/*
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "1970-01-01 18:43:06.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}*/

Совершенно неинтуитивно, что в разобранную дату в данном случае подставится текущее время. У меня даже нет идей для чего это могло бы пригодиться. А чтобы текущее время не подставлялось, нужно использовать символ «восклицательный знак» или «вертикальная черта»:

var_dump(DateTime::createFromFormat("!d.m.Y", "01.01.1970"));
/*
object(DateTime)#1 (3) {
  ["date"]=>
  string(26) "1970-01-01 00:00:00.000000"
  ["timezone_type"]=>
  int(3)
  ["timezone"]=>
  string(3) "UTC"
}*/
2018   php   программирование

Загрузка на «Спектруме»

Игра «Ливингстон, я полагаю?», созданная испанскими разработчиками в ноябре 1986 года, выпускалась и версия под ДОС

Примерно три года моего детства были отданы компьютеру «Спектрум», с ним я проводил подавляющую часть своего свободного времени — играл, программировал, перепаивал. Игры хранились на обычных аудиокассетах (позже появились модели с дисководами, но не у меня) и средняя игра загружалась около пяти минут.

Мощи́ у компьютера хватало лишь на небольшое разрешение 256×192, пиксели были по современным меркам чудовищной величины и чтобы их ещё больше не растягивать, но сделать экран зрительно больше, создатели «Спектрума» сделали вокруг экрана специальную одноцветную область «бордюра» — используя 254-й порт ей можно было задавать один из небольшого набора цветов.

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

Так выглядел процесс загрузки стандартным загрузчиком

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

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

Мы с братишкой тоже поучаствовали в общем безумии — приделали к игре «Ливингстон, я полагаю?», которая на скриншоте, загрузчик собственного изготовления, помню моя была идея и графика, а братишка больше программировал.

Не помню трогали ли мы область бордюра, скорее да, чем нет, но что точно помню — мы тогда сделали загрузку заставки «змейкой», а после подключалась анимация — Ливингстон в гамаке качал ножкой, а птица (не помню какая из двух) махала крыльями.

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

Недавно разговаривали с братишкой на эту тему, с удовольствием вспоминали то время.

Любопытно было бы взглянуть на тот загрузчик сейчас, но боюсь очень мало шансов, что где-то могла уцелеть кассета с этой модифицированной игрой. Скорее всего наши труды растворились в шуме Вселенной.

2018   speccy   программирование

Файл, состоящий из нулей

Если вы не понимаете, что тут делает эта картинка, не пугайтесь, это мем, их развелось столько, что обо всех и не узнаешь

Предпринимаю вторую попытку посмотреть на язык программирования «Раст», первую я предпринимал, когда язык бурно развивался и меня быстро утомила скорость с которой устаревают примеры.

Почитал руководство, написал «Песню о пиве», теперь попробовал решить более практическую задачу — у одного нашего клиента после восстановления сбойной файловой системы часть файлов занулилась — внутри них одни байты с кодом ноль. Сейчас надо бы её просканировать и восстановить из бакапа всё испортившееся.

В общем, попробовал написать нужную утилиту на «Расте», если кто его вдруг знает, покритикуйте, кода там совсем немного.

2018   rust   программирование
Ранее Ctrl + ↓