Skip to content

Latest commit

 

History

History
369 lines (311 loc) · 29.2 KB

KittenDB_Lists.wiki

File metadata and controls

369 lines (311 loc) · 29.2 KB

Здесь находится описание интерфейса к KittenDB (List Engine), используемого для хранения большого количества списков целых чисел (например, списков участников группы).

Table of Contents

Система хранения списков целых чисел

Основная идея - обеспечивается хранение большого количества списков List_i (идентифицируемых целым числом i) целых чисел, с возможностью указать для каждого элемента дополнительные атрибуты (байт флагов + 32-битное значение, а также неявно указанную дату добавления) и сортировки в антихронологическом порядке. Примеры возможного использования:

  • group members: список List_i содержит участников группы i;
  • member_groups: список List_i содержит группы, в которые вступил/приглашен/подал заявку пользователь i
  • app_fans: список List_i содержит пользователей, установивших приложение i
  • fan_apps: список List_i содержит приложения, установленные пользователем i.
  • fan_members: список List_i содержит список пользователей, поклонником которых является пользователь i
  • member_fans: список List_i содержит список поклонников пользователя i

Расширения

  • Lists-X -- позволяет использовать в качестве list_id и/или object_id вектора из нескольких целых чисел.
  • Lists-Y -- позволяет хранить и получать, но не сохранять 64-битные value.
  • Lists-Z = Lists-X + Lists-Y.

Байт флагов

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

  • бит 0 (+1) -- заявка одобрена пользователем;
  • бит 1 (+2) -- заявка одобрена со стороны администратора списка (т.е. группы или приложения);
  • бит 2 (+4) -- заявка соответствует событию, а не группе.
В итоге комбинированное значение этих двух битов означает следующее:
  • 0 -- такого не должно быть (запись удалена?).
  • 1 -- пользователь подал заявку в группу, но она еще не утверждена.
  • 2 -- пользователю прислали приглашение в группу, но он его еще не принял.
  • 3 -- пользователь состоит в группе.
Таким образом, для получения списка всех групп, в которых состоит пользователь, нужно вытащить все записи с flags & 7 == 3, а для получения всех событий - с flags & 7 == 7.

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

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

Значение

32-битное или 64-битное число, связанное с каждой записью списка. Может быть использовано, например, для хранение количества "денег", которых пользователь положил на свой счет в приложении, или же для хранения id того, кто пригласил в группу или приложение.

Обращение к List Engine из PHP

$MC_Lists = new Memcache ($ip, $port, ...);

Возвращает объект для доступа к списку с указанным номером, либо false, если такого объекта нет или соответствующий сервер сейчас недоступен.

Далее доступ к данным осуществляется по аналогии с memcached, с помощью функций вроде
$result = $MC_Lists->get($key);
$MC_Lists->set($key,$value,0,600);
$MC_Lists->delete($key);
$MC_Lists->increment($key,$value);
для специально построенных ключей $key и значений $value.

Терминология

При описании функций будем использовать следующие термины:

Список (List) Список, идентифицируется целым числом i; состоит из записей
Запись (Entry) То, из чего состоят списки; содержит ссылку на объект и дополнительные данные (время добавления, флаги, значение)
Объект (Object) То, на что ссылается запись; идентифицируется целым числом j.
Флаг (Flag) Байтовый атрибут записи, учет которого возможен при чтении списка
Значение (Value) 32-битный атрибут записи, используется для хранения дополнительных данных о записи
Текст (Text) Необязательное текстовое поле из не более 255 байтов, связанное с записью
Следует подчеркнуть, что в каждом списке содержится не более одной записи, ссылающейся на данный объект, т.е. пара (номер списка, номер объекта) однозначно определяет запись и может быть использована для доступа к ней.

Список доступных функций

Удаление списка

delete("list$id")
Удаляет список $id, если он существовал. Снова создать список можно, добавив туда новую запись.

Удаление объекта

delete("object$id")
или (лучше)
delete("$list@object$id")
Удаляет все записи, относящиеся к объекту $id во всех списках (или во всех списках, хранимых на том же сервере, что и $list). В первой форме запрос является "диагональным": при дроблении данных на несколько экземпляров lists-engine необходимо слать запрос не самому (какому?) lists-engine, а mc-proxy либо rpc-proxy, осуществляющему распределение запросов на сервера. Вторая форма производит удаление только на выбранном сервере, даже если отсылается через mc-proxy.

Удаление записи

delete("entry$list_$oid")
Удаляет в списке $list запись, ссылающуюся на объект $oid.

Добавление записи

set("entry$list_$oid", "$flags,$value")
Добавляет запись с объектом $oid в список $list, а если она уже есть, то перезаписывает.

Редактирование записи

replace("entry$list_$oid", "$flags,$value")
Редактирует уже существующую запись, при этом ее поле text не меняется.

Создание новой записи

add("entry$list_$oid", "$flags,$value")
Создает запись, если ее еще нет.

Изменение текста записи

set("text$list_$oid", $text)
Изменяет текст записи об объекте $oid в списк $list. Значение - произвольная строка из не более чем 255 символов. Если передана пустая строка, текст удаляется.

Изменение флагов существующей записи

set("flags$list_$oid", $flags)
replace("flags$list_$oid", $flags)
set("flags$list_$oid", "$set,$clear")
replace("flags$list_$oid", "$set,$clear")
increment("flags$list_$oid", $flag_incr)
decrement("flags$list_$oid", $flag_decr)
В данном случае первые формы равнозначны и приводят к изменению флагов уже существующей записи. Третья и четвертая формы также эквивалентны, аргументом является строка "$set,$clear", состоящая из маски $set флагов, которые надо установить, и маски $clear флагов, которые надо сбросить. Флаги, не попавшие ни в $set, ни в $clear, не изменяются.
Наконец, последние две формы также изменяют флаги у уже существующей записи; при этом они используют логическое, а не арифметическое сложение и вычитание.

Изменение значения записи

set("value$list_$oid", $value)
replace("value$list_$oid", $value)
increment("value$list_$oid", $value_incr)
decrement("value$list_$oid", $value_decr)
Изменяет значение 32-битного параметра, связанного с существующей записью. Никаких проверок на переполнение не производится.

Увеличение значения записи с ее созданием в случае отсутствия

get("incr_value{$list}_{$oid}_{$flags}+={$value_incr}")
Увеличивает значение value элемента $oid списка $list на $value_incr и возвращает итоговое значение.
Если указанного элемента не существует, он создается с нулевым значением (которое сразу же увеличивается на $value_incr) и с флагами $flags. Если произошла внутренняя ошибка или получилось -2^63, возвращается строка "FAILED"; переполнение при операции не проверяется. Значение $value_incr не может превосходить по модулю 2^31 - 1.

Изменение флагов у заданного подсписка

set("listflags$list,$flags", $new_flags)
set("listflags$list,$flags", "$or_mask,$nand_mask")
set("listflags$list,$xor_mask,$and_mask", "$or_mask,$nand_mask")
Выбирает все записи из списка list с flags & 7 == $flags, и меняет им флаги. В первой форме флаги устанавливаются равными $new_flags; во второй форме биты из $nand_mask сбрасываются, после чего устанавливаются биты из $or_mask.

Удаление подсписка

delete("list$list,$flags")
delete("list$list,$xor_flags,$and_flags")
Удаляет из списка $list все записи с переданным значением flags & 7. Во второй форме - с (flags ^ $xor_flags) & $and_flags == 0.

Получение записи

get("entry$list_$oid")
Возвращает содержимое указанной записи в виде строки "$flags,$value,$date,$global_id", или даже "$flags,$value,$date,$global_id,0,0,0,0,$text", если запись есть. Поле $text может содержать любые символы, в том числе запятые.

Получение флагов записи

get("flags$list_$oid")
Возвращает содержимое флагов записи в виде строки с десятичной записью.

Получение значения записи

get("value$list_$oid")
Возвращает 32-битное значение записи в виде строки с десятичной записью.

Получение текста записи

get("text$list_$oid")
Возвращает текст, связанный с указанной записью, из не более чем 255 символов.

Вычисление позиции записи в списке

get("entry_pos$list_$oid")
Возвращает позицию объекта $oid в списке $list. Более точно: возвращает количество элементов списка $list, не превосходящих $oid, уменьшенное на единицу. Если списка нет или он пуст, возвращается -1.

Вычисление позиции записи в подсписке

get("entry_sublist_pos$list_$oid_$mode") 
Возвращает позицию объекта $oid в подсписке $list. Более точно: возвращает количество элементов списка $list, не превосходящих $oid, уменьшенное на единицу. Если списка нет или он пуст, возвращается -1. 

Получение списка

Получение всего списка

get("list$list")
get("list$list,$mode")
get("list$list,$mode#$limit")
get("list$list,$mode#$limit,$offset")
Возвращает содержимое списка $list, если такой есть, в соответствии с режимом, переданным в $mode.
Если передано значение $limit, возвращается не больше указанного количества записей.
Различные биты режима $mode имеют следующий смысл

+0 Выдавать весь список
+1 Выдавать только записи с (flags & 7) == 1
+2 Выдавать только записи с (flags & 7) == 2
+3 Выдавать только записи с (flags & 7) == 3
... Выдавать только записи с (flags & 7) == ...
+7 Выдавать только записи с (flags & 7) == 7
+8 Выдавать только записи с (flags & 7) == 0
+0 Выдавать список в порядке возрастания id объекта
+16 Выдавать список в порядке убывания id объекта
+32 Выдавать список в хронологическом порядке
+48 Выдавать список в антихронологическом порядке
+0 Выдавать только id объектов
+64 Выдавать также флаги объектов
+128 Выдавать также дату создания записей
+256 Выдавать также глобальные идентификаторы записей
+512 Выдавать также значения (value) записей
+1024 Выдавать также тексты (text) записей

Результат возвращается в виде строки, состоящей из десятичных записей чисел, разделенных запятыми.
Первое число - это всегда общее количество записей $size в ответе (без учета отсечения по $limit).
Далее следуют описание min($size,$limit) записей, каждая из которых кодируется одним, двумя, тремя, четырьмя или пятью целыми числами в зависимости от того, какие именно поля, помимо id объектов, были запрошены.
В том случае, если требуется вернуть тексты записей, после этих целых чисел следует текст, также отделенный запятой. В самом тексте при этом запятые заменяются на символ с кодом 12, а символ с кодом 12 - на пробел.

Получение размера списка

get("count$list")
get("count$list,$mode")
Возвращают только длину запрошенного списка (в первой форме) или его подсписка (во второй форме; при этом $mode есть номер подсписка от 0 до 8). Функционально эквивалентны запросам get("list$list,$mode#0") с $limit=0, однако допускают только значения $mode от 0 до 8; при этом get("count$list") или get("count$list,8") эквивалентен get("list$list,0#0"), а get("count$list,0") эквивалентен get("list$list,8#0"). Ответ - это либо строка с десятичной записью одного числа, либо ничего (false), если списка не существует.

Получение размера списка и его подсписков

get("counts$list")
Возвращает общую длину запрошенного списка, а также восьми его подсписков, характеризующихся свойством flags & 7. Результат - строка из девяти целых чисел, разделенных запятыми.

Пересечение списка с заданным списком объектов

set("temp$tag", "$obj1,$obj2,...,$objN") <br> $result = get("intersect$list,$mode,$tag") <br> $result = get("intersect$list,$mode,$tag#$limit")
Здесь $tag - случайное число от 1 до 109, используемое для идентификации временного списка объектов. После того, как этот список отослан, второй запрос пересекает переданный временный список со списком $list, используя при этом параметр $mode (принимающий значения от 0 до 8 для выбора запрошенного подсписка, и кроме того, флаги +64, +128, +256, +512, +1024 для указания того, какие дополнительные поля должны быть возвращены), и возвращает результат пересечения в виде списка $oid, упорядоченных по возрастанию, вместе с дополнительными параметрами, аналогично тому, как это делает get list. Временный список должен содержать не более 10000 объектов. Во второй форме возвращается случайная выборка из $limit элементов, упорядоченных по возрастанию.

Разность списка с заданным списком объектов

set("temp$tag", "$obj1,$obj2,...,$objN") <br> $result = get("subtract$list,$mode,$tag") <br> $result = get("subtract$list,$mode,$tag#$limit")
Здесь $tag - случайное число от 1 до 109, используемое для идентификации временного списка объектов. После того, как этот список отослан, второй запрос вычитает из временного списка список $list, используя при этом параметр $mode (принимающий значения от 0 до 8 для выбора запрошенного подсписка), и возвращает результат пересечения в виде списка $oid, упорядоченных по возрастанию. Временный список должен содержать не более 10000 объектов. Во второй форме возвращается случайная выборка из $limit элементов, упорядоченных по возрастанию.

Вычисление количества или суммы весов объектов в заданном списке

set("temp$tag", "$obj1,$obj2,...,$objN")
или
set("xtemp$tag", "$obj1#$weight1,$obj2#$weight2,...,$objN#$weightN")
$result = get("sumlist$list,$mode,$tag")
Здесь $tag - случайное число от 1 до 109, используемое для идентификации временного списка объектов. В форме xtemp можно передать также веса каждого объекта (32-битные целые). В формате temp веса предполагаются равными единице. Далее запрос работает аналогично intersect, однако возвращаемое значение - это не пересечение временного списка с указанным списком, а сумма весов объектов из этого пересечения (строка с десятичной записью 64-битного числа). Отметим, что после одного set temp или set xtemp можно запросить сразу несколько ключей вида sumlist, intersect и subtract в одном get'е.

Использование подотрезков

При использовании sumlist или intersect в temp или xtemp массивах можно указывать не только $object_id, но и целый отрезок из $object_id. Делается это так: если $object_id состоит из нескольких целых чисел, то можно указать, только несколько первых - это будет обозначать, что оставшиеся числа могут быть любыми. Единственным требованием является то, что при использовании нескольких подотрезков они все обязательно должны быть одного размера (то есть от каждого должно быть указано одинаковое число int).

Пример:
set temp20 "66697211,72912054"
get intersect154,0,20

result:
6,66697211:1801:11,72912054:1416925:11,72912054:1416932:11,72912054:158952728:8,72912054:159091021:8,72912054:160338854:8

Получение начала списка, отсортированного по value

Возвращает начало списка (или его подсписка), отсортированным по value и global_id:

get("sortedlist$list,$xor_mask,$and_mask,$mode#$limit")

Возвращается список, для которого выполняется условие ((FLAGS ^ $xor_mask) & $and_mask) == 0, или, что почти одно и то же, FLAGS & $and_mask == $xor_mask. $limit должен быть строго положителен.

+0 Выдавать список в порядке возрастания value объекта, при совпадении - по возрастанию date
+1 Выдавать список в порядке возрастания value объекта, при совпадении - по убыванию date
+2 Выдавать список в порядке убывания value объекта, при совпадении - по возрастанию date
+3 Выдавать список в порядке убывания value объекта, при совпадении - по убыванию date
+0 Выдавать только id объектов
+64 Выдавать также флаги объектов
+128 Выдавать также дату создания записей
+256 Выдавать также глобальные идентификаторы записей
+512 Выдавать также значения (value) записей
+1024 Выдавать также тексты (text) записей

Результат возвращается в виде строки, состоящей из десятичных записей чисел, разделенных запятыми.
Первое число - это всегда общее количество записей $size в ответе (без учета отсечения по $limit).
Далее следуют описание min($size,$limit) записей, каждая из которых кодируется одним, двумя, тремя, четырьмя или пятью целыми числами в зависимости от того, какие именно поля, помимо id объектов, были запрошены.
В том случае, если требуется вернуть тексты записей, после этих целых чисел следует текст, также отделенный запятой. В самом тексте при этом запятые заменяются на символ с кодом 12, а символ с кодом 12 - на пробел.

Получение распределения элементов списка или подсписка по дате создания

get("datedistr$list,$mode#$min_date,$max_date,$step")
Возвращает массив из N+2 целых чисел, где N = ($max_date - $min_date) / $step, i-ое (0 < i <= N) из которых представляет собой количество элементов списка $list (если $mode = 0) или его подсписка $mode (если $mode=1..15, выбирается подсписок ($mode & 7)), со значением даты создания $date в диапазоне $min_date + (i-1)*$step <= $date < $min_date + i*$step. Нулевой элемент массива - количество элементов с $date < $min_date, последний (N+1-ый) - с $date >= $max_date.

Массив возвращается в виде строки, состоящей из десятичных записей N+3 чисел (первое из них - N+2), разделенных запятыми. Ограничения: $max_date > $min_date > 0, $max_date - $min_date делится на $step, N <= 16384.

Если список мог бы быть в данном куске, но его реально нет, возвращается строка "0". В случае ошибки обычно возвращается false (отсутствие ключа).