Что же мне делать, что же мне делать, чтожемнеделать, через 10 часов самолёт, надо что-то решать
Вроде я себя чувствую получше после амоксициллина.
Отличные новости
Похоже, у меня нет метастаз в лёгкие, это просто пневмония </sarcasm>
День, когда WordPress подавился метадатой
Сегодняшняя история програмистская. Кому компьютеры скучны, можете смело пропускать.
Как все знают, у меня есть отдельный блог на boku.ru. Записи туда по большей части копируются отсюда – в виде исключения я пару раз выложил там скучные рассказы, чтобы включить их в архив, но не афишировать.
Блог сделан на WordPress. Копирование записей устроено так: специальный скрипт генерирует RSS из дневника на Diary, а плагин FeedWordPress забирает RSS и импортирует в WordPress.
Категории при этом сохраняются, внутренние ссылки мой собственный плагин заменяет на местные, а если пост на дайри изменился – изменяется и пост на boku.ru, так что всё устроено достаточно удобно.
Но есть проблема. (далее)
function WhatToDo(post) localPost = FindLocalCopy(post); if localPost==null then //New post! AddPostMeta(localPost, 'syndication_item_hash', post.Hash); return doCreateNewPost; else if not FindMeta(localPost, 'syndication_item_hash', post.Hash) then //Post changed! AddPostMeta(localPost, 'syndication_item_hash', post.Hash); return doUpdatePost; else //No changes. return doNothing;
Если пост на дайри не менялся, FeedWordPress не будет заново его импортировать и не создаст новой ревизии местного поста. Это хорошо. Но перед тем, как записать пост в базу, WordPress прогоняет его через ряд плагинов, которые меняют его содержание:
Пост на дайри (из RSS) –> (замена ссылок на местные) —-> (исправление форматирования) –> Пост на boku.ru
Бывает, что какой-то из плагинов сбоит, и преобразует пост неправильно. Тогда я начинаю искать, в чём дело. Чтобы разобраться, мне нужно импортировать пост снова и снова, пока я не найду ошибку.
Но как это сделать? Ведь пост уже импортирован, и с точки зрения FeedWordPress, его содержимое не менялось (на дайри он остался тем же).
Для этой цели я влез в файлы FeedWordPress, и временно покромсал описанную выше процедуру. Она стала выглядеть так:
function WhatToDo(post) localPost = FindLocalCopy(post); if localPost==null then //New post! AddPostMeta(localPost, 'syndication_item_hash', post.Hash); return doCreateNewPost; else if not FindMeta(localPost, 'syndication_item_hash', post.Hash) then //Hack: Post is always changed! AddPostMeta(localPost, 'syndication_item_hash', post.Hash); return doUpdatePost; //TODO: Restore normal version.
Менялся пост или нет, мы всегда импортируем его заново. Конечно, при этом создаётся новая ревизия и захламляется база, но подумаешь, мне же ненадолго… А старые ревизии поста легко удалить.
Поправив таким образом FeedWordPress, я залил новые файлы на сервер и стал искать баг в своих плагинах. И нашёл. Исправил. Убедился, что теперь посты преобразуются правильно. Всё сохранил, применил, закрыл… а отключить хак забыл.
И ушёл.
Вторая половина этой истории началась через месяц, когда я зашёл на блог на boku.ru. Все страницы с последними постами не работали.
Вместо них отображался белый экран. Не работала даже консоль админа, из которой посты можно удалить. В логах сервера появлялась ошибка:
php error: maximum memory allocation exceeded
Какой-то из скриптов жрёт память? Но почему? Что я менял?
И тут я вспомнил, что забыл отключить хак.
Но постойте, а что такого? Проверки раз в полчаса – это 48 проверок в день, жалкие полторы тысячи ревизий за месяц. WordPress может обслуживать десятки тысяч постов, для MySQL лишние несколько тысяч ревизий – пустяк.
Если я напишу ещё полторы тысячи постов – вордпресс даже не поперхнётся. А полторы тысячи ревизий вывели его из строя?
Да ну! Не так он написан.
Тогда почему любая страница, которая обращается к последним постам – вылетает с переполнением памяти? База данных находится на диске – что вообще вордпресс грузит в память?
Метадату.
Каждый раз, загружая очередной пост для печати, вордпресс делает примерно следующее:
rows = exec_sql('SELECT * FROM post_metadata WHERE post_id=id'); while rows.MoveNext() do metadata[rows['name']]=rows['value']
То есть, читает из базы все относящиеся к посту записи метадаты и загружает их для быстрого доступа в память.
Обычно таких записей 8-10, иногда до 15 – мелочи, в общем.
У последних записей в моём блоге их было по 60 000.
Ничего удивительного, что обращаясь к этим записям, вордпресс падал. Он не рассчитан на 60 000 записей метадаты у поста. Удивительно, откуда эти записи взялись.
Я открыл таблицу phpMyAdmin-ом, и увидел, что все они – это копии параметра syndication_permalink. Тогда всё стало ясно.
Описанная выше функция WhatToDo решает, что делать с постом из RSS – добавить новый, обновить существующий или пропустить. При этом она регистрирует syndication_permalink, чтобы второй раз не обновлять одно и то же.
Да, импорт RSS происходит лишь раз в полчаса, 48 раз в сутки, и каждый пост импортируется лишь однажды – но функция проверки WhatToDo вызывается десятки раз за процедуру одного импорта. Только однажды её результат имеет значение, поэтому ревизий в базе действительно создано лишь полторы тысячи – но при каждом вызове она добавляет syndication_permalink, и этих пермалинков, совершенно одинаковых, у одного поста набираются десятки тысяч.
Ирония: вордпресс мог бы вынести десятки тысяч постов – но не десятки тысяч свойств поста.
Как всё это чинить?
Итак, испорчена таблица post_metadata: в ней для некоторых постов некоторые записи продублированы десятки тысяч раз. Нужно удалить дубли, но оставить по одной копии каждой записи.
После некоторой возни и гуглинга сотворился следующий манёвр:
CREATE TABLE `keep_ids` AS ( SELECT MIN(`rowid`) AS `rowid` FROM `post_metadata` GROUP BY `postid`, `name`, `value` )
Этим запросом мы находим все цепочки дублей (записей с одинаковыми данными в полях postid, name и value), и в каждой выбираем наименьший номер записи. Таким образом, мы получаем по одной копии каждой уникальной записи. Эти копии надо сохранить, а всё остальное удалить.
ALTER TABLE `keep_ids` ADD UNIQUE INDEX `rowid` (`rowid`)
Это чтобы операции с новой таблицей были быстрыми – сейчас понадобится.
DELETE FROM `post_metadata` WHERE `rowid` NOT IN (SELECT `rowid` FROM `keep_ids`)
Удаляем все записи из исходной таблицы, которые не вошли в наш “список на сохранение”. Если б в `keep_ids` не было индексов, мы бы тут завязли на несколько минут, а так – только секунд.
Ну и, наконец, удаляем временную таблицу:
DROP TABLE `keep_ids`
Победа! Число записей в post_metadata резко падает с сотен тысяч до 13 000 и блог снова работает нормально.
Названия таблиц и полей в примерах условны, и не соответствуют настоящим названиям в базе вордпресс. Код написан на условном языке, а код SQL может быть не совсем правильным, но передаёт общую мысль.
Ну вот, похоже, девятого числа я еду в Японию. Хотя чувствую себя по-прежнему нехорошо (после последней химии). Надеюсь, всё в ближайшие дни как-нибудь разрешится: либо мне резко станет лучше или хуже, либо придут результаты каких-нибудь анализов, которые любые путешествия исключат, и т.д. и т.п.. А то непонятно как-то.
В Токио я буду неделю, при этом попадаю на летний комикет (10-12) и, возможно, Обон (15 августа, но в Канто 15 июля, короче, я ничего не понял, разберусь ближе к делу).
Надо вспомнить все места, которые я хотел посетить. Подскажите что-нибудь интересное. Пока помню:
– Комикет
– Акибу
– Синдзюку
– Токийскую башню
– Сибую
– Это место где продают отоме-игры (забыл место)
– Посмотреть на Токийский залив
– Обон
Принимаю запросы на сувениры, также на покупки с комикета (поскольку заранее неясно, что будет на комикете, и что я из этого увижу, можно просить и в общих чертах, например, “додзи по ореимо манами х папа кёске”, и тогда я, скрепя сердце, постараюсь найти хоть что-нибудь в таком духе).
Разумеется, нужно уметь как-то у меня это потом забрать. Обычно я в Москве.
Ещё аниме пачками
Kokoro connect – ещё пять школьников открыли кружок времяпровождения.
Binbougami ga! – ещё один сверхъестественный кто-то поселился в доме у кого-то.
Jinrui wa suitai shimashita – что-то из ноитамины, очередной непонятный мир будущего, мало сюжета, все такие необычные девочки, феечки, какая-то соц. сатира (но в сто раз менее едкая, чем в зецубо сенсее), в общем, кому-то может понравиться… скорее, девушкам.
Sword Art Online – чуваки зашли в виртуальную реальность и не могут выйти. Капля интереса в завязке есть, но похоже, впереди просто 13 серий приключенчества.
Получил свою японскую визу
Выглядит как радужная наклейка во всю страницу загранпаспорта.
Заодно сравнил последнее фото с тем, что на загранке (circa 2010). Два года назад я был вежливый молодой человек, а сейчас бандит какой-то лысый
Я не уверен!
Попробуйте быстро ответить на вопрос, в ответе на который не уверены до конца:
– Ты дома свет выключил?
– По-моему, да.
Не годится! “По-моему” – это сокращение от “по моему мнению” (“По-моему, Пупкин – плохой президент”), а какое уж тут мнение? Либо выключил, либо нет.
– Кажется, да.
Не годится! “Казаться” могут предметы вдалеке (“Кто это там на эшафоте?” – “Ба! Кажется, Пупкин”), ну в крайнем случае, будущее (“Кажется, Пупкину кранты”), но никак не прошлое! Где это оно “кажется” (показывается)?
– Вроде бы да.
Не годится! “Вроде” значит “похожего рода, сорта” (“Чья это дача?” – “Вроде бы депутата какого-то”). Вы же со светом поступили вполне определённо, либо выключили, либо нет.
– Полагаю, да.
Не годится! Полагают верным то, на чём строят дальнейшие рассуждения (“Полагаю, здесь теперь не искупаться, так что надо искать новый пляж”). А тут речь о ваших сомнениях, а не предположениях.
– Наверное.
Не годится! Какое же это “на верное”, когда вы не уверены? Правильное употребление: “Почему стоим?” – “Наверное, депутата везут.”
– Возможно.
Не годится! А то мы не знали, что это возможно! Правильное употребление: “Возможно, будет революция”.
– Видимо.
Что это вам “видимо”, когда дом далеко-далеко? Правильное употребление: “Что солдаты там делают?” – “Видимо, охраняют мир и порядок.”.
– Скорее всего.
А что, было соревнование в скорости выключения света? Правильно – указать на событие, которое случится прежде любых других: “Скорее всего, президент выступит с заявлением.”.
– Да выключил я, выключил, отвяжись от меня!
О договорах
Раньше я думал, что я один такой, но похоже, в головах очень многих людей сидит мысль, что договор на бумаге – это формальность, а главное договориться по-человечески. Заказываю у одной фирмы, скажем, покупку и посадку картошки. Посидели, поговорили, выдают мне договор на подписание. Читаю:
Исполнитель обязуется посадить картошку на поле заказчика.
И ни слова про то, откуда он её возьмёт.
Я спрашиваю:
– А почему не сказано про то, что картошку вы купите сами?
– Да-да, купим, мы же договорились.
– Но в договоре об этом не сказано…
– Купим, откуда ещё нам взять картошку?
Приставать к менеджеру стыдно – мы ведь договорились! Получается, я им не доверяю? Я крючкотвор, придираюсь к бумажке?
Но договор и существует на случай, если мы поссоримся. Никому не хочется ссориться, но если слепо верить в чужую порядочность, то договоры вообще не нужны, правильно? Не надо ничего писать – ни про покупку, ни про посадку. А раз уж начали, то дело следует довести до конца. Неправильный договор – хуже, чем вообще никакого.
– Давайте, всё-таки, укажем это в договоре. А то, если мы поссоримся, вы скажете – “кто говорил о покупке? Мы вашу картошку обещали посадить”.
– Хорошо, не проблема. Не будем ссориться. (сделал) Раньше просто никто не просил такого.
У этой достаточно крупной фермерской фирмы были десятки клиентов. Ни один не прочёл договора и не попросил указать в нём всё правильно? Либо менеджер говорит неправду, либо эти люди – растяпы, такие же, как я (если бы не обдумал это заранее).
Памятка исправляющимся растяпам:
Читайте от начала и до конца каждый договор, который подписываете. Не стесняйтесь потратить чужое время или задержать очередь – в крайнем случае, отойдите в уголок. Всегда просите разъяснения непонятным местам, и если формулировка договора вам не нравится, или вам кажется, что в нём сказано неясно, не то или не всё, о чём договорились, просите договор исправить.
Ни один договор не написан в камне, это всё вордовские документы, и пусть вас не пугает, что слова уже распечатаны: изменить текст и распечатать заново – дело минуты. Не сдавайтесь при словах, что “такой договор подписывают все”: платить за ЭТОТ договор придётся вам, а не “всем”, вы и решаете, что в нём написано.
Если вы и ваш партнёр действительно договорились, нет никаких причин не изменить договор, чтобы прояснить обязанности сторон или описать их полнее.
Отказать вам могут тогда – и только тогда! – когда вас хотят обмануть.
Игра по Back to the Future
Конечно, это фанфик, но очень хороший фанфик. Настолько кинематографичный и похожий на оригинал, что сцены из игры в голове путаются со сценами из фильма. Даже сюжет, который местами выбивается из стилистики, по большому счёту всё-таки “настоящий” – приключенческий и интересный. Не перечесть всех моментов, когда думаешь “чёрт, а ведь это правда могло быть и в фильмах”.
А знакомая музыка и знакомые голоса Марти и Дока (трудно поверить, что их играли другие люди) сшивают любые разрывы и заставляют поверить, что это действительно “Назад в будущее”. Авторы могли ошибиться во стольких местах, но в большинстве не ошиблись.