Tarantool CE/EE Documentation portal logo
Помощь
Обновлена 15 сентября 2026 г. в 08:55

Расширения MessagePack

Tarantool использует предопределенные типы расширений MessagePack для представления некоторых специальных значений. Типы расширений включают MP_DECIMAL, MP_UUID, MP_ERROR, MP_DATETIME и MP_INTERVAL. Эти типы требуют особого внимания со стороны разработчиков коннекторов, поскольку их необходимо обрабатывать отдельно от стандартных типов MessagePack и корректно сопоставлять с типами языка программирования.

Тип DECIMAL

Тип расширения MessagePack MP_EXT вместе с типом расширения MP_DECIMAL является заголовком для значений типа DECIMAL.

Тип MP_DECIMAL равен 1.

Спецификация MessagePack определяет два вида типов:

  • Типы fixext 1/2/4/8/16 имеют фиксированную длину, поэтому длина не кодируется явно.
  • Типы ext 8/16/32 требуют явного кодирования длины данных.

MP_EXP + необязательный length подразумевают использование одного из этих типов.

Представление decimal в MessagePack выглядит следующим образом:

<table class="tableblock frame-all grid-all stretch"><colgroup><col style="width: 20%;"><col style="width: 40%;"><col style="width: 20%;"><col style="width: 20%;"></colgroup><thead><tr><th class="tableblock halign-left valign-top">{decodeBase64(IE1QX0VYVA==)}</th><th class="tableblock halign-left valign-top">{decodeBase64(IGxlbmd0aCAob3B0aW9uYWwp)}</th><th class="tableblock halign-left valign-top">{decodeBase64(IE1QX0RFQ0lNQUw=)}</th><th class="tableblock halign-left valign-top">{decodeBase64(IFBhY2tlZERlY2ltYWw=)}</th></tr></thead></table>

Здесь length – длина поля PackedDecimal, имеет тип MP_UINT, если кодируется явно (т.е. когда используется тип ext 8/16/32).

PackedDecimal имеет следующую структуру:

<--- length bytes --><table class="tableblock frame-all grid-all stretch"><colgroup><col style="width: 50%;"><col style="width: 50%;"></colgroup><thead><tr><th class="tableblock halign-left valign-top">{decodeBase64(IHNjYWxl)}</th><th class="tableblock halign-left valign-top">{decodeBase64(IEJDRA==)}</th></tr></thead></table>

Здесь scale – значение типа MP_INT или MP_UINT.
scale = количество цифр после десятичной точки

BCD – последовательность байтов, представляющих десятичные цифры закодированного числа (каждый байт содержит две десятичные цифры, каждая из которых кодируется 4-битным nibble), поэтому byte >> 4 – первая цифра, а byte & 0x0f – вторая цифра. Крайняя левая цифра в массиве является старшей. Крайняя правая цифра в массиве является младшей.

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

|  4 bits           |  4 bits           |   = 0x                = the 1st digit

(Первый nibble содержит 0, если десятичное число имеет четное количество цифр.) Последний байт массива BCD содержит последнюю цифру числа и завершающий nibble, представленные следующим образом:

|  4 bits           |  4 bits           |   = the last digit    = nibble

Завершающий nibble представляет знак числа:

  • 0x0a, 0x0c, 0x0e, 0x0f – плюс,
  • 0x0b и 0x0d – минус.

Примеры

Десятичное число -12.34 будет закодировано как 0xd6,0x01,0x02,0x01,0x23,0x4d:

|MP_EXT (fixext 4) | MP_DECIMAL | scale |  1   |  2,3 |  4 (minus) ||       0xd6       |    0x01    | 0x02  | 0x01 | 0x23 | 0x4d       |

Десятичное число 0.000000000000000000000000000000000010 будет закодировано как 0xc7,0x03,0x01,0x24,0x01,0x0c:

| MP_EXT (ext 8) | length | MP_DECIMAL | scale |  1   | 0 (plus) ||      0xc7      |  0x03  |    0x01    | 0x24  | 0x01 | 0x0c     |

Тип UUID

Тип расширения MessagePack MP_EXT вместе с типом расширения MP_UUID для значений типа UUID. Начиная с версии 2.4.1.

Тип MP_UUID равен 2.

Спецификация MessagePack определяет d8 как fixext с размером 16, а размер UUID всегда равен 16. Поэтому представление UUID в MessagePack выглядит следующим образом:

<table class="tableblock frame-all grid-all stretch"><colgroup><col style="width: 25%;"><col style="width: 25%;"><col style="width: 50%;"></colgroup><tbody><tr><td class="tableblock halign-left valign-top"><p class="tableblock">{decodeBase64(IE1QX0VYVCAgPSBkOA==)}</p></td><td class="tableblock halign-left valign-top"><p class="tableblock">{decodeBase64(IE1QX1VVSUQgID0gMg==)}</p></td><td class="tableblock halign-left valign-top"><p class="tableblock">{decodeBase64(IFV1aWRWYWx1ZSAgPSAxNi1ieXRlIHZhbHVl)}</p></td></tr></tbody></table>

16-байтовое значение содержит 2 цифры на байт. Как правило, оно состоит из 11 полей, которые кодируются как целые числа без знака в порядке big-endian следующим образом:

  • time_low (4 байта)
  • time_mid (2 байта)
  • time_hi_and_version (2 байта)
  • clock_seq_hi_and_reserved (1 байт)
  • clock_seq_low (1 байт)
  • node[0], ..., node[5] (по 1 байту)

Некоторые функции из модуля uuid могут возвращать значения, совместимые с типом данных UUID. Например, после

uuid = require('uuid')box.schema.space.create('t')box.space.t:create_index('i', {parts={1,'uuid'}})box.space.t:insert{uuid.fromstr('f6423bdf-b49e-4913-b361-0740c9702e4b')}box.space.t:select()

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

d8 02 f6 42 3b df b4 9e 49 13 b3 61 07 40 c9 70 2e 4b

Тип ERROR

Начиная с версии 2.4.1, ответы об ошибках содержат дополнительную информацию после данных, описанных в Протокол Box – ответы об ошибках. Это «совместимое» расширение, поскольку клиенты, ожидающие ответов сервера в старом формате, должны игнорировать неизвестные им компоненты map. Однако обратите внимание, что было переименовано имя константы: раньше IPROTO_ERROR в ./box/iproto_constants.h было 0x31, теперь IPROTO_ERROR0x52, а IPROTO_ERROR_240x31.

Тип MP_ERROR равен 3.

<table class="tableblock frame-all grid-all stretch"></table>                        MP_MAP

Дополнительная информация, большая часть которой также присутствует в полях объекта error:

MP_ERROR_TYPE (0x00) (MP_STR) Тип, указывающий на источник, как в {error_object}.base_type, например "ClientError".

MP_ERROR_FILE (0x01) (MP_STR) Файл исходного кода, в котором была перехвачена ошибка, как в {error_object}.trace.

MP_ERROR_LINE (0x02) (MP_UINT) Номер строки в файле исходного кода, как в {error_object}.trace.

MP_ERROR_MESSAGE (0x03) (MP_STR) Текст причины ошибки, как в {error_object}.message. Значение здесь будет тем же, что и в значении IPROTO_ERROR_24.

MP_ERROR_ERRNO (0x04) (MP_UINT) Порядковый номер ошибки, как в {error_object}.errno. Не путать с MP_ERROR_ERRCODE.

MP_ERROR_ERRCODE (0x05) (MP_UINT) Номер ошибки, определенный в errcode.h, как в {error_object}.code, который также можно получить с помощью C-функции box_error_code(). Значение здесь будет тем же, что и в младшей части значения Response-Code-Indicator.

MP_ERROR_FIELDS (0x06) (MP_MAPs) Дополнительные поля, зависящие от типа ошибки. Например, если MP_ERROR_TYPE – "AccessDeniedError", то MP_ERROR_FIELDS будет включать "object_type", "object_name", "access_type". Это поле будет опущено в теле ответа, если дополнительные поля отсутствуют.

Разработчикам клиентов и коннекторов следует убедиться, что неизвестные ключи map игнорируются, а также проверять добавление новых ключей в исходном файле Tarantool, где определено создание объекта ошибки. В версии 2.4.1 этот файл исходного кода называется mp_error.cc.

Например, в версии 2.4.1 или более поздней, при попытке создать дубликат спейса с помощью
conn:eval([[box.schema.space.create('_space');]])
ответ сервера будет выглядеть следующим образом:

ce 00 00 00 88                  MP_UINT = HEADER + BODY SIZE83                              MP_MAP, size 3 (i.e. 3 items in header)  00                              Response-Code-Indicator  ce 00 00 80 0a                  MP_UINT = hexadecimal 800a  01                              IPROTO_SYNC  cf 00 00 00 00 00 00 00 05      MP_UINT = sync value  05                              IPROTO_SCHEMA_VERSION  ce 00 00 00 4e                  MP_UINT = schema version value82                              MP_MAP, size 2  31                              IPROTO_ERROR_24  bd 53 70 61 63 etc.             MP_STR = "Space '_space' already exists"  52                              IPROTO_ERROR  81                              MP_MAP, size 1    00                              MP_ERROR_STACK    91                              MP_ARRAY, size 1      86                              MP_MAP, size 6        00                              MP_ERROR_TYPE        ab 43 6c 69 65 6e 74 etc.       MP_STR = "ClientError"        02                              MP_ERROR_LINE        cd                              MP_UINT = line number        01                              MP_ERROR_FILE        aa 01 b6 62 75 69 6c etc.       MP_STR "builtin/box/schema.lua"        03                              MP_ERROR_MESSAGE        bd 53 70 61 63 65 20 etc.       MP_STR = Space.'_space'.already.exists"        04                              MP_ERROR_ERRNO        00                              MP_UINT = error number        05                              MP_ERROR_ERRCODE        0a                              MP_UINT = error code ER_SPACE_EXISTS

Тип DATETIME

Начиная с версии 2.10.0. Тип расширения MessagePack MP_EXT вместе с типом расширения MP_DATETIME является заголовком для значений типа DATETIME. Он создает контейнер с полезной нагрузкой размером 8 или 16 байт.

Тип MP_DATETIME равен 4.

Спецификация MessagePack определяет d7 как fixext с размером 8, а d8 – как fixext с размером 16.

Поэтому представление datetime в MessagePack выглядит следующим образом:

<table class="tableblock frame-all grid-all stretch"><colgroup><col style="width: 25%;"><col style="width: 25%;"><col style="width: 25%;"><col style="width: 25%;"></colgroup><thead><tr><th class="tableblock halign-left valign-top">{decodeBase64(IE1QX0VYVCAgPSBkNy9kOA==)}</th><th class="tableblock halign-left valign-top">{decodeBase64(IE1QX0RBVEVUSU1FICA9IDQ=)}</th><th class="tableblock halign-left valign-top">{decodeBase64(IHNlY29uZHM=)}</th><th class="tableblock halign-left valign-top">{decodeBase64(IG5zZWM7IHR6b2Zmc2V0OyAgdHppbmRleDs=)}</th></tr></thead></table>

Данные MessagePack содержат:

  • Секунды (8 байт) как незакодированное 64-битное целое число со знаком, сохраненное в порядке little-endian.
  • Необязательные поля (8 байт), если любое из них имеет ненулевое значение. Поля включают nsec, tzoffset и tzindex, упакованные в порядке little-endian.

Подробнее о типе datetime см. подробности о типе поля datetime и описание модуля datetime.

Тип INTERVAL

Начиная с версии 2.10.0. Тип расширения MessagePack MP_EXT вместе с типом расширения MP_INTERVAL является заголовком для значений типа INTERVAL.

Тип MP_INTERVAL равен 6.

Интервал сохраняется как вариант map с предопределенным количеством известных имен атрибутов. Если некоторые атрибуты не определены, они опускаются в формируемой полезной нагрузке.

Представление interval в MessagePack выглядит следующим образом:

<table class="tableblock frame-all grid-all stretch"><colgroup><col style="width: 14.2857%;"><col style="width: 42.8571%;"><col style="width: 14.2857%;"><col style="width: 28.5715%;"></colgroup><tbody><tr><td class="tableblock halign-left valign-top"><p class="tableblock">{decodeBase64(IE1QX0VYVA==)}</p></td><td class="tableblock halign-left valign-top"><p class="tableblock">{decodeBase64(IFNpemUgb2YgcGFja2VkIGludGVydmFs)}</p></td><td class="tableblock halign-left valign-top"><p class="tableblock">{decodeBase64(IE1QX0lOVEVSVkFM)}</p></td><td class="tableblock halign-left valign-top"><p class="tableblock">{decodeBase64(IFBhY2tlZEludGVydmFs)}</p></td></tr></tbody></table>

Упакованный интервал состоит из:

  • Упакованного количества ненулевых полей.
  • Упакованных ненулевых полей.

Каждое упакованное поле имеет следующую структуру:

<table class="tableblock frame-all grid-all stretch"><colgroup><col style="width: 33.3333%;"><col style="width: 66.6667%;"></colgroup><thead><tr><th class="tableblock halign-left valign-top">{decodeBase64(IGZpZWxkIElE)}</th><th class="tableblock halign-left valign-top">{decodeBase64(IGZpZWxkIHZhbHVl)}</th></tr></thead></table>

Количество определенных (ненулевых) полей может быть равно нулю. В этом случае упакованный интервал будет закодирован как целое число 0.

Список идентификаторов полей:

  • 0 – год
  • 1 – месяц
  • 2 – неделя
  • 3 – день
  • 4 – час
  • 5 – минута
  • 6 – секунда
  • 7 – наносекунда
  • 8 – корректировка

Пример

Значение интервала 1 years, 200 months, -77 days кодируется следующим образом:

tarantool> I = datetime.interval.new{year = 1, month = 200, day = -77}---...tarantool> I---- +1 years, 200 months, -77 days...tarantool> M = msgpack.encode(I)---...tarantool> M---- !!binary xwsGBAABAczIA9CzCAE=...tarantool> tohex = function(s) return (s:gsub('.', function(c) return string.format('%02X ', string.byte(c)) end)) end---...tarantool> tohex(M)---- 'C7 0B 06 04 00 01 01 CC C8 03 D0 B3 08 01 '...

Где:

  • C7 – MP_EXT
  • 0B – размер упакованного значения интервала (11 байт)
  • 06 – тип MP_INTERVAL
  • 04 – количество определенных полей
  • 00 – идентификатор поля (год)
  • 01 – упакованное значение 1
  • 01 – идентификатор поля (месяц)
  • CCC8 – упакованное значение 200
  • 03 – идентификатор поля (день)
  • D0B3 – упакованное значение -77
  • 08 – идентификатор поля (корректировка)
  • 01 – упакованное значение 1 (DT_LIMIT)

Подробнее о типе interval см. подробности о типе поля interval и описание модуля datetime.