LINUX.ORG.RU
ФорумTalks

Программистских баек тред

 ,


0

2

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

Начну.

История первая.

У меня кусок админки управляет кучкой фоновых процессов. Не напрямую, а через прослойку-супервизора. Прослойку я написал на PHP, чтобы задействовать уже готовые функции админки. А чтобы управлять фоновыми процессами, потребовалось на php из подручных средств соорудить аналог pidfile_open (3). Вот такой:

function readPidfile($pidfile) {
    /* XXX: Race conditions are everywhere. But who cares? */

    if (!file_exists($pidfile)) {
        /* No such file - daemon not running */
        return false;
    }

    $f = fopen($pidfile, "r");
    if (!$f) {
        /* Failed to open file - daemon probably not running */
        return false;
    }

    if (flock($f, LOCK_EX | LOCK_NB)) {
        /* Able to acuire lock - daemon not running */
        fclose($f);
        return false;
    }

    /* Return PID */
    $pid = fgets($f);
    return $pid;
}

Вот смотрю и думаю: какое-то нецелевое использование «макропроцессора для HTML-страниц». Ну а почему бы и нет. Работает же.

История вторая.

Сегодня пришлось повоевать с кодировками в icecast. icecast к кодировкам оказался не очень приспособлен. Вот написал им, может замерджат мой патч: https://gitlab.xiph.org/xiph/icecast-server/-/issues/2423

Но что-то сомнительно. Ход очевидный, но почему-то сами они его не делали.

а ты в одиночку работаешь? команды нету?

TDrive ★★★★★
()

PHP норм для скриптинга. Ну всяко лучше баша!

Но JavaScript (нода) - еще лучше. Там, конечно, придется скачать с npm пачку пакетов про работу с системными ресурсами, но дальше крутень, нормальный язык

stevejobs ★★★★☆
()
Ответ на: комментарий от theNamelessOne

Причина банальна, я и так за… устал, кароч.

А завтра я забью, так как уже накатил патч локально. Так что написал, пока помню.

wandrien ★★
() автор топика

Была уже такая тема, но не взлетела: Байки из склепа

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

WitcherGeralt ★★
()
Последнее исправление: WitcherGeralt (всего исправлений: 2)
Ответ на: комментарий от WitcherGeralt

Нэ было такого, начальника! Это Ашот прод из стойки уронил, эээээ, кланус!

wandrien ★★
() автор топика
Ответ на: комментарий от theNamelessOne

А, вспомнил. У них вроде там кому-то на почту надо писать, чтобы дали права на клонирование репы и MR.

Развели инстансов гитлаба со своими правилами, понимаешь)

wandrien ★★
() автор топика
Ответ на: комментарий от stevejobs

Слабо ты свою IDE продвигаешь? Сибиряк - одно слово!

lochness
()

Хотел поддержать, но вспомнил, что чукча не писатель. Всю пятницу трахался с постгресом на маке и только к вечеру вспомнил, что GNU и BSD отличаются, поэтому просто скачал маковский пакет и все заработало. Вот перечитай это предложение, оно и на 1% не описывает всю пережитую боль и драму. А если бы я мог красиво писать, то писал бы не на лорчик, а порнороманы за кучу бабок.

Lordwind ★★★★★
()
Ответ на: комментарий от Lordwind

Вот перечитай это предложение, оно и на 1% не описывает всю пережитую боль и драму.

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

Вон за тем патчем в icecast на самом деле стоит 3 часа работы с попутным исправлением багов еще в одном продукте, но описать это в красках не получится.

и только к вечеру вспомнил, что GNU и BSD отличаются, поэтому просто скачал маковский пакет и все заработало

Хм, а мак по внутрянке классифицируется как BSD? Я как-то уже и забыл о том, что они родственны. Там снизу их собственное ядро, сверху их уникальный прикладной API, а где-то посередине этот невидимый BSD остался.

wandrien ★★
() автор топика
Ответ на: комментарий от WitcherGeralt

на маке докер хренова работает, точно не для базы

TDrive ★★★★★
()

а если без проверки file_exists делать запрос на открытие файла для чтения? что изменится?

xmikex ★★★★
()

Писал на С++. Решил заменить отдельные min и max на minmax. Потом компания потратила 3 человеконедели на поиск трудновоспроизводимой ошибки, иногда дающей неверный результат вычислений на некоторых платформах.

Минимальный пример невалидного кода:

#include <iostream>
#include <algorithm>

int getx1(){return 0;}
int getx2(){return 1;}

int main()
{
    auto min_max = std::minmax(getx1(), getx2());

    auto min = std::min(getx1(), getx2());
    auto max = std::max(getx1(), getx2());
    
    std::cout << "ok:" << min << " " << max << "\n";
    std::cout << "undefined behavour:" << min_max.first << " " << min_max.second << "\n";
    return 0;
}

Почему последний вывод в cout невалидный - остаётся заданием для лоровцев.

GPFault ★★
()
Последнее исправление: GPFault (всего исправлений: 1)
Ответ на: комментарий от GPFault

Почему последний вывод в cout невалидный - остаётся заданием для лоровцев.

У minmax аргументы объявлены как (const T& a, const T& b), и возвращает в результате он такие же ссылки, а не полновесные копии объектов. Соответственно передавать в него временные объекты с временем жизни в один sequence point — плохая идея.

Вот так кресты позволяют в прыжке с кульбитом выстрелить себе в ногу.

wandrien ★★
() автор топика
Ответ на: комментарий от GPFault

Почему последний вывод в cout невалидный - остаётся заданием для лоровцев.

Потому что возвращается пара со ссылками.

Очевидно.

Потом компания потратила 3 человеконедели на поиск трудновоспроизводимой ошибки

Переходите на Rust, сэконите по 3 человеконедели на каждой такой ошибки…

fsb4000 ★★★★★
()
Ответ на: комментарий от xmikex

Не по феншую. Нарушает гармонию мира.

ну варнинги можно отключить.

Тогда в другом месте что-нибудь важно можно не заметить.

wandrien ★★
() автор топика
Ответ на: комментарий от WitcherGeralt

Для модульных тестов идея использует embedded postgres, но тащит его с собой, докер не используется.

Lordwind ★★★★★
()
Ответ на: комментарий от fsb4000

C-way — документировать все проёбы дизайна ЯП как UB вместо исправления их.

C++-way — позволить всем желающим самостоятельно создавать шаблоны любых UB, какие только они захотят!

wandrien ★★
() автор топика
Ответ на: комментарий от xmikex

В Си fopen() себя нормально ведёт, а в PHP свой особый путь — матюкаться ворнингами в лог.

wandrien ★★
() автор топика
Ответ на: комментарий от fsb4000

Как раз задумался о расте после этого; хотя это был самый сильный по степени «время поиска/рискованность на вид при внесении» косяк. Баги, на которые было потрачено по 2-3 человеко недели были и другие, но всё же не настолько неожиданные.

Типа того что abs(1.1f) на MSVC возвращало 1.1f, а на gcc+linux вначале приводило к int и возвращало 1. Тут код не мой, а был 10 лет до меня, я только на gcc+linux переносил. std::abs и fabs проблему с рахницей поведения на компиляторов не имеют, только abs.

GPFault ★★
()
Последнее исправление: GPFault (всего исправлений: 1)

Я вчера узнал, что numpy и вообще питоновская экосистема говнокод.

Вроде обычно питонисты хвалят эту либу…

Они нарушают ODR и делают UB. И это как-то раньше работало, а теперь перестало.

https://github.com/microsoft/STL/issues/2335

https://github.com/pybind/pybind11/issues/3459

fsb4000 ★★★★★
()
Ответ на: комментарий от WitcherGeralt

как ты эпично прод завалил, например

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

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

Этот рост, в свою очередь, был наглядно виден на графике. Соответственно, если график медленно, но верно полз вверх, кто-нибудь должен был приконнектиться к базе данных, найти нехорошее сообщение, и сделать DELETE FROM messages WHERE messageId=... — ну, на самом деле, там была Mnesia, а не SQL, но принцип таков. После этого график так же медленно, но верно начинал ползти вниз.

И я один раз, действуя по этому сценарию, приконнектился к базе данных, набрал DELETE FROM messages... и нажал Enter.

Через секунду график ухнул до нижней границы. Где-то минут через пятнадцать начальник нашего отдела задумчиво сказал «кто-то решил проблему кардинальным способом». Я, на всякий случай, притворился, что не слышал. Более никаких последствий не было.

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

Проблема возникла, когда я слегка намудрил с миграцией, и генерация сообщений пошла быстрее, чем обработка. В результате в очереди скопилось, по-моему, 60 миллионов сообщений, и они очень неспешно обрабатывались. Это жрало ресурсы и, в результате, многие ДРУГИЕ сообщения, необходимые для работы системы, не проходили вовремя. Прод начал ощутимо тормозить.

Сообщений были записаны, опять-таки, в базе. На сей раз — MySQL. Зная, что моё понимание MySQL, мягко говоря, не идеально, я пошёл к нашему DBA. Обнаружил, что DBA ушёл на обед. Тогда я поймал другого девопса, с поэтическим именем Аттила, очень умного парня, и объяснил ему ситуацию. Показал, сколько сообщений в базе (при помощи SELECT COUNT), и спросил, можно ли мне их все просто грохнуть. Аттила пожал плечами и сказал «да пожалуйста». Я сделал DELETE и убедился, что на сей раз не забыл WHERE.

Через минуту в чате посыпались отчаянные вопли «помогите, прод не работает вообще».

Как оказалось, мы напоролись на replication lag. Все ресурсы MySQL уходили на синхронизацию — мастер-ноде нужно было про каждое из этих 60 миллионов сообщений объяснить всем остальным нодам, что этих сообщений больше нет. В итоге всё остальное — то есть, всё реально важное — перестало работать от слова «совсем».

К счастью, вернувшийся DBA как-то пофиксил проблему. Я не знаю, как именно, и не очень хочу. Насколько я знаю, ему пришлось отрубить системе все конечности, чтобы сохранить её жизнь.

На следующий день начальник вызвал меня и DBA к себе, чтобы разобраться в ситуации. Среди прочего он сказал «давайте теперь каждое изменение в базе воспринимать как пулл-реквест: кто-то должен сделать ревью». Я только разинул рот, как DBA меня опередил и сказал «вообще-то, так и было — Аттила посмотрел на SQL-запрос и одобрил. Говорит, что неправильно прочитал, сколько там записей». Начальник кивнул головой, сказал «ну что ж, shit happens», и отпустил нас обоих с миром.

Вот.

Miguel ★★★★★
()

Файловый деcкриптор забыл закрыть.

pid не проверил на число и на > 0

Не проверил существование pid.

vel ★★★★★
()
Ответ на: комментарий от xmikex

ну варнинги можно отключить. оно же не завершается с ошибкой от этого?

2021 год. PHP-шники до сих пор отключают варнинги.

Это всё, что вам нужно знать про PHP.

Miguel ★★★★★
()
Ответ на: комментарий от vel

Файловый деcкриптор забыл закрыть.

Эпично. Пойду исправлю. Вот не зря тему создал)

pid не проверил на число и на > 0

А и хрен с ним.

Не проверил существование pid.

Если лок кто-то держит, значит процесс жив.

wandrien ★★
() автор топика
Ответ на: комментарий от xmikex

ну функция установки уровня предупреждений для чего-то же сделана.

Для дебилов.

wandrien ★★
() автор топика
Ответ на: комментарий от WitcherGeralt

Виндопроблемы?

Да. Но вполне могут быть и Linux проблемы где-то в другом месте.

fsb4000 ★★★★★
()
Ответ на: комментарий от vel

Файловый деcкриптор забыл закрыть.

Вспомнил, о чем я думал. Его сборщик мусора приберёт. Это же не просто дескриптор, а в GC всё завернуто.

Но когда он его приберёт, хз, так что лучше явно закрыть.

А насчёт остального.

  1. С гарантией убедиться, что данные корректны, мы всё равно не сможем.
  2. Даже если мы как-то убедились в этом, процесс мог сдохнуть сразу после чтения нами PID. И вызывая kill, вовсе не факт, что мы стреляем в нужного.

Ну можно добавить один уровень костылей, хотя смысла особо нет:

function _readPidfile($pidfile) {
    /* XXX: Race conditions are everywhere. But who cares? */

    if (!file_exists($pidfile)) {
        /* No such file - daemon not running */
        return false;
    }

    $f = fopen($pidfile, "r");
    if (!$f) {
        /* Failed to open file - daemon probably not running */
        return false;
    }

    if (flock($f, LOCK_EX | LOCK_NB)) {
        /* Able to acuire lock - daemon not running */
        fclose($f);
        return false;
    }

    /* Return PID */
    $pid = fgets($f);
    fclose($f);
    return $pid;
}

function readPidfile($pidfile) {

    $pid1 = false;
    $pid2 = true;

    while ($pid1 !== $pid2) {
        $pid1 = _readPidfile($pidfile);
        sleep(0.1);
        $pid2 = _readPidfile($pidfile);
    }

    return $pid1;
}
wandrien ★★
() автор топика
Последнее исправление: wandrien (всего исправлений: 1)
Ответ на: комментарий от Miguel

И я один раз, действуя по этому сценарию, приконнектился к базе данных, набрал DELETE FROM messages… и нажал Enter.

Классика!

wandrien ★★
() автор топика
Ответ на: комментарий от GPFault

Типа того что abs(1.1f) на MSVC возвращало 1.1f, а на gcc+linux вначале приводило к int и возвращало 1.

Прикольно, я не знал.

Да, это именно gcc+linux.

clang+linux возвращает 1.1

https://gcc.godbolt.org/z/rsPYzKseY

Наверное gcc даже формально прав…

Если импортировать из math.h то он выведет 1.1: https://gcc.godbolt.org/z/rcv566c51

А, ну да. Оба варианта возможны:

https://en.cppreference.com/w/cpp/header

the corresponding cxxx headers are allowed to also declare the same names in the global namespace: including «cstdlib» definitely provides std::malloc and may also provide ::malloc

fsb4000 ★★★★★
()
Последнее исправление: fsb4000 (всего исправлений: 5)
Ответ на: комментарий от wandrien

Если лок кто-то держит, значит процесс жив.

Вот ты его как раз и держишь пока не закроешь файл или не отменишь блокировку.

vel ★★★★★
()
Ответ на: комментарий от vel

Вот ты его как раз и держишь пока не закроешь файл или не отменишь блокировку.

Перечитай. Блокировку я отменяю сразу как только получил.

wandrien ★★
() автор топика
Ответ на: комментарий от wandrien

Да, но разработчик под винду 10 лет прежде этого не знал - и много лет применял её для float. Тогда стандарт был не в моде. А когда настало время потртировать - всё собирается, запускается, но «минорные различия в результатах расчётов» с отладкой и поиском причин на недели.

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

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

GPFault ★★
()
Последнее исправление: GPFault (всего исправлений: 1)
Ответ на: комментарий от wandrien

Перечитай. Блокировку я отменяю сразу как только получил.

перечитал 2 раза, но unlock так и не нашел. Или ты имел ввиду, что файл закрыл - lock отпустил.

Выкини file_exists(). Оно тут нафиг не нужно. Кроме того, оно еще кеширование использует.

vel ★★★★★
()
Ответ на: комментарий от vel

Или ты имел ввиду, что файл закрыл - lock отпустил.

Внезапно.

wandrien ★★
() автор топика
Ответ на: комментарий от vel

Файловый деcкриптор забыл закрыть.

Зенд уже умеет определять отсутствие ссылок на ресурс и автоматически его удалять.

fernandos ★★★
()
Ответ на: комментарий от Miguel

Жиза. Я однажды тоже снёс данные из Бд, но успешно достал их из бекапа. И коллеги не раз сносили, там зачастую было более драматично.

WitcherGeralt ★★
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.