Друпалеру на заметку

Если у вас по каким-то причинам есть запись в таблице node, но нет ни одной записи с таким nid в node_revisions, то у вас ВНЕЗАПНО начнут портиться права доступа. Причем rebuild permissions будут помогать ненадолго, до попытки создания очередной node.

Детектируется проблема элементарно:

 select nid from node n where not exists (select nid from node_revisions r where r.nid=n.nid);
Лечится - таким же delete.

Но я сегодня чуть не фалломорфировал, разбираясь.

Почему создание записи с revision не обернуто в транзакцию - мне удивительно, но подозреваю что это привет от MySQL.

Comments

Было бы желание у пЕсателей, и в мыскуле бы смогли бы транзакцию сделать. Просто привыкли к автокоммиту, любители .DBF-переростка.

У меня случился тяжелый затык. Я пытаюсь написать программу на CUDA, которая должна тупым перебором инкрементируемого аргумента выделить те его значения, на которых некая функция выдаёт положительный результат. Сама функция нетривиальная, но считается довольно быстро, многие десятки миллионов в секунду получаются. Искомых значений аргумента на несколько порядков меньше, чем их всего проверяется, но сильно больше одного.

Затык случился на методике возврата найденных значений в хост. Я попробовал через глобальный массив со счетчиком использованных слотов, который потом считывается в хост.

Простейший условный оператор if (res !=0) { дописать arg в возвращаемый массив } сокращает производительность на несколько порядков. Это даже без использования семафора, который по-хорошему таки нужен.

Ты случайно не знаешь, как принято поступать в подобных случаях?

Я не вполне понимаю твою задачу, но вот например:
- писать в выходной массив всегда (пару вход/результат)
- потом их отсортировать по результату.

У тебя же проблема не только в if(res) но и в том, что счетчик надо считать из глобальной памяти, потом записать что-то куда-то (относительно рандомная локация в рамках треда), потом и счетчик записать тоже.

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

А сколько этих самых ненулевых результатов, ну примерно?

Если их совсем мало, то удивительно что оно у тебя тормозит на проверке, которая не срабатывает.

Если их относительно много - то накопить все результаты и потом, отсортировав, выкинуть ненужное - будет быстрее.

примерно один-два на миллион

И что if(..) globalArray[atomicAdd(&counter,1)]=index тормозит весь процесс на порядки? Удивительное рядом.

Даже не atomic. Простая условная запись даже в одну и ту же ячейку тормозит процесс на порядки.
if(match) {
matchingArgs[0] = arg;
}

arg представляет собой unsigned char[8].
matchingArgs - глобальный массив, объявленный с атрибутом __device__. (Если быть совсем точным, это часть структуры, состоящей из счетчика, семафора, флага переполнения и собственно массива, но не думаю, что это принципиально).

А если написать if(1), что вероятно оптимизируется компилятором в отсутствие if вообще, то торможения практически нет. То есть, проблема не в самой по себе записи, а именно в её условности.

Так существуют какие-то идеологически более правильные способы возвращать такие наборы результатов?

По идее, такие 1-2 команды должны оптимизироваться в команду с предикатом т.е. конечно пока в одном треде варпа она исполняется - все остальные будут стоять, но и все.

А че профайлер говорит про это? Он, конечно, не operator-level (уроды), но об какое место тормозит можно, наверное, понять.

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

Профайлер еще не пробовал, за идею спасибо, она мне почему-то в голову не пришла :)

А я тут подумал, куря на балконе, что если у тебя результат вызова функции нигде не используется, то не мог ли оптимизатор просто весь этот вызов спилить вникуда?

Функция имеет тип void, а результат возвращает в переменную через переданный ей указатель. Если компилятор решил такое заоптимизировать в ноль, то его аффторов надо гнать погаными тряпками вон из профессии.
Надо будет проверить, правда ли это..

Э, ну если указатель был на shared, а потом это место никак не используется - то я бы заоптимизировал.

Но тогда запись *всех* результатов в global mem - тоже должна быть "медленной" в том смысле, что не оптимизированной в ноль

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

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

Именно так.

Чтоб было понятнее, о чем речь, вот тестовый пример: http://dil.pp.ru/xfer-test.zip

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

Если у функции включить побочный эффект в виде инкрементирования элемента глобальной структуры (инкрементирование работает, его видно потом в хосте): 1497 миллионов проверок.

Добавляем безусловное инкрементирование другого элемента глобальной структуры после вызова функции: 1320 миллионов.

Переносим это инкрементирование внутрь if(1): ничего не меняется.

Меняем условие на if(result): скорость уменьшается в три раза, 467 миллионов/c.

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

Не, ну это ненастоящий код, ты же пишешь по одному адресу в __device__. Че там с (например) кэшами и конфликтами вообще неясно.

Кэшироваться должно хорошо, я ж в одно место пишу :)
С конфликтами в случае безусловной записи должно быть ещё хуже, все треды пишут одновременно, а с условием только очень некоторые. А получается всё равно сильно медленнее.

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

Но сам факт буквально всенародной любви к мусклю при том, что есть более-менее нормальная реализация sql - необъясним.

Объясним, это DBF 21-го века!

Я думал на эту роль назначен SQLite.

Про SQLite не все знают.

На самом деле очень просто объясним. Берем шаред хостинг, и смотрим сколько хостеров дают мускуль, а сколько - постгрес ...

А любов хостеров к мыскулю ты чем объяснишь? "Берём..." -- что?

дешевизной миннимально достаточного решения? :)

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

Да не, современный мыскуль уже почти хорош в плане транзакционности. Другое дело, что нормальные запросы там бывает сложно написать, но последователям .DBF не привыкать. Собственно, фиг с ним, с мыскулем, раз уж пЕсатели его выбрали, но можно же иногда без автокоммита работать?

Это, я так понимаю, в шестерке? Надо будет посмотреть, сохранился ли этот баг в семерке, там работа с БД существенно переделана, в том числе и в части поддержки транзакций.

Не так и просто на это налететь, обычно оно на полдороге не ломается.

Но ломается - да, больно.