Как стать автором
Обновить
15
0

Пользователь

В MySQL есть возможность указывать используемую кодировку для каждой конкретной колонки, поэтому для совсем новых данных это решается очень просто:
alter table `my_table` add column `my_column` varchar(n) character set utf8mb4;

(и, разумеется, set names utf8mb4 вместо set names utf8)
Если вдруг символы с четырехбайтовым представлением в UTF-8 появляются в колонке, которая определена как utf8mb3, то такой символ просто заменяется на знак вопроса (при условии set names utf8mb4, если используется utf8mb3, то строка внезапно обрежется по такому символу).
Каждый исходник отдельно переводится «на юникод» т.е. добавляются эти преобразования (при этом сам код конвертируется в UTF-8, ставится use utf8, и любую строковую константу тоже нужно обработать такими преобразованиями, перед любым не-ASCII регэкспом их тоже нужно выполнить над исходными данными).

Именно чтобы избежать этого мы и использовали перловые фильтры. Более того, забыл про это написать, мы вместо use utf8 использовали use my::utf8. Особенность нашей прагмы как раз в том, что она применяется условно, в зависимости от той самой константы enabled. Чтобы не быть голословным, приведу еще кусочек кода из этого модуля на эту тему (source_in_utf8 меняется с 0 на 1 при конвертации git-репо, это делается уже после переключения на utf8):
package my::utf8;

use Filter::Util::Call;

sub source_in_utf8 () { 0 }
sub enabled () { $utf8_enabled }

my %FILTERING;
my $UTF8_ENC = Encode::find_encoding('UTF-8'); # Use strict version of UTF-8 to prevent invalid data
my $CP1251_ENC = Encode::find_encoding('cp1251');

sub import {
    my ($class, %args) = @_;
    my $filename = ($args{level} ? caller($args{level}) : caller())[1];
    if (source_in_utf8 && enabled) {
        goto &utf8::import;
    } elsif (source_in_utf8) {
        unless ($FILTERING{$filename}) {
            filter_add(sub {
                my $status = filter_read();
                Encode::from_to($_, $UTF8_ENC, $CP1251_ENC) if $status > 0;
                return $status;
            });
            $FILTERING{$filename} = 1;
        }
    } elsif (enabled) {
        unless ($FILTERING{$filename}) {
            filter_add(sub {
                my $status = filter_read();
                Encode::from_to($_, $CP1251_ENC, $UTF8_ENC) if $status > 0;
                return $status;
            });
            $FILTERING{$filename} = 1;
        }
        goto &utf8::import;
    }
    return;
}

sub unimport {
    my ($class, %args) = @_;
    my $filename = ($args{level} ? caller($args{level}) : caller())[1];
    if (source_in_utf8 && enabled) {
        goto &utf8::unimport;
    } elsif (source_in_utf8) {
        filter_del();
        delete $FILTERING{$filename};
    } elsif (enabled) {
        filter_del();
        delete $FILTERING{$filename};
        goto &utf8::unimport;
    }
    return;
}


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

К счастью, у нас весь ввод/вывод большей частью сосредоточен в нескольких местах: ввод/вывод веб-сервера (разбор get/post параметров, шаблонизатор, аяксы, апишка), клиентики к хранилищам, взаимодействие с внешними системами.

сколько человек в течение какого срока занимались Perl частью?

Собственно perl-часть заняла не так много времени, если посчитать время всех задействованных разработчиков, то вряд ли больше шести-восьми человеконедель. Точно сложно сказать, так как чисто перловых задач было всего несколько, а большинство правок было связано с необходимостью обеспечить плавное и постепенное переключение хранилищ в другую кодировку.
Совсем ничего не делать в таком случае не получилось. Мы завели функцию, которая в зависимости от конфигурации сервера (cp1251 или UTF-8) принимала решение о том, как именно перекодировать. Заменили все такие явные преобразования в коде (к счастью, их было не так много, в пределах 200, — это посильная задача), и только после этого стали переключать.
open my $f, ">", "report.file";
my::utf8::encode_any($data, 1);
print $f $data;
close $f;

И ниже, собственно как эти функции реализованы (на самом деле их десяток на все случаи жизни). Сразу оговорюсь по стилю: отсутствие копирования входных параметров и оператора return — принесено в жертву производительности — это разумно для однострочных частовызываемых функций; модификация аргумента in-place и возвращаемый значения — для совместимости с utf8::encode/decode, в будущем это позволит удалить костылики почти не задумываясь.
sub enabled () { $utf8_enabled }

my $UTF8_ENC = Encode::find_encoding('UTF-8'); # Use strict version of UTF-8 to prevent invalid data
my $CP1251_ENC = Encode::find_encoding('cp1251');

if (enabled) {
    *encode_any = sub ($$) { $_[0] = Encode::encode($_[1] ? $UTF8_ENC : $CP1251_ENC, $_[0]); () };
    *decode_any = sub ($$) { $_[0] = Encode::decode($_[1] ? $UTF8_ENC : $CP1251_ENC, $_[0]); 1 };
} else {
    *encode_any = sub ($$) { Encode::from_to($_[0], $CP1251_ENC, $UTF8_ENC) if $_[1]; () };
    *decode_any = sub ($$) { Encode::from_to($_[0], $UTF8_ENC, $CP1251_ENC) if $_[1]; 1 };
}

Красочные смайлики технически тоже шрифты. Я так понимаю, что у этих шрифтов больше вес для диапазонов с пиктограммками, как результат они используются вместо черно-белых.
Это один из вариантов. Второй, вероятный вариант, использование смайликов, которые появились в последних версиях Unicode (7.0.0, например, добавляет приличное их количество) и которых нету в установленных на системе шрифтах. У меня, например, половина таблиц на странице en.wikipedia.org/wiki/Emoji в квадратиках. Скорее всего это решается установкой/обновлением пакетов с шрифтами.
Не ошибаетесь, проекту Мой Мир и правда 7 лет. Но изначально он вылился из Почты в виде проектов Блоги, Фото и Видео, который использовали кодовую базу почты (и часть БД тоже). Потом из Блогов образовался Мир, а также произошло его слияние с Фото и Видео.
Насчет увеличения длины ключа индекса думали, но решили, что не хотим увеличивать без лишней необходимости: все-таки индекс всегда съедает память по максимальному варианту. Пришлось, конечно, повозиться и убедиться в том, что наши строки уникальны на выбранную длину, и конфликтов на уникальных индексах не возникает.
Что касается utf8mb4, согласен, это неприятная проблема. Когда выбирали между utf8mb3 и utf8mb4, мы посчитали, что можем пожертвовать редкими языками в пользу экономии памяти в индексах. Но, к сожалению, не подумали про emoji. Хорошо, что в MySQL у нас почти что нет данных, в которых применение emoji было бы особенно критично (диалоги, лента, комментарии хранятся в специализированных хранилищах). Спасибо, что обратили на это внимание, мы проведем исследование на тему того, насколько это может быть критично для нас, и, возможно, придется принять меры.
Причина, думаю, у большинства проектов, использующих морально устаревшие кодировки, одна: рождение проекта (кодовой базы) в те времена, когда использование многобайтовых кодировок требовало слишком много усилий, а эффект от этого в пределах Рунета бал минимальный. У нас в коде до сих пор встречаются строки, датированные 2000 годом :)
Спасибо, что помогли сделать Мир чуть лучше! Мобильный лис, тем более с планшета, зверь нечастый, закралась для него ошибка в конфигурации, починили.
Для предпродакшн-тестирования, не только очередей, но и проекта в целом, у нас используется отдельная инсталляция всех наших сервисов на альфа-кластере. Особенность конфигурации кластера в том, что весь исполнимый код — тестовый, а хранилища при этом используются из продакшена. Но для сервера очередей, так как он хранит все-таки не данные, а потоки команд, делается исключение, и у нас есть отдельный тестовый инстанс, с которым взаимодействует проверяемый код. Так как обработчики самостоятельно запрашивают задания у сервера очередей, то сконфигурировать такую инсталляцию довольно просто.
Что касается тестирования новых/модифицируемых обработчиков самим разработчиком, то на виртуальной машине каждого разработчика помимо веб-сервера также поднимается сервер очередей и один универсальный слот, который умеет обрабатывать задания всех типов.

Информация

В рейтинге
Не участвует
Работает в
Зарегистрирован
Активность