Ключевое пространство
Deno KV — это хранилище ключ-значение. Ключевое пространство — это плоское пространство имён пар ключ+значение+временной отметки версии. Ключи — это последовательности частей ключа, которые позволяют моделировать иерархические данные. Значения — произвольные объекты JavaScript. Временные отметки версии указывают, когда значение было вставлено/изменено.
Ключи
Ключи в Deno KV — это последовательности частей ключа, которые могут быть strings, numbers, booleans, Uint8Arrays или bigints.
Использование последовательности частей вместо одной строки устраняет возможность атак с инъекцией разделителей, так как никакого видимого разделителя нет.
Атака с инъекцией ключа происходит, когда злоумышленник манипулирует структурой хранилища ключ-значение, вводя разделители, используемые в схеме кодирования ключа, в управляемую пользователем переменную, что приводит к нежелательному поведению или несанкционированному доступу. Например, рассмотрим хранилище ключ-значение, использующее косую черту (/) в качестве разделителя, с ключами, такими как «users/alice/settings» и «users/bob/settings». Злоумышленник может создать нового пользователя с именем «alice/settings/hacked», чтобы сформировать ключ «users/alice/settings/hacked/settings», введя разделитель и манипулируя структурой ключа. В Deno KV инъекция приведёт к ключу
["users", "alice/settings/hacked", "settings"], что не представляет опасности.
Между частями ключа используются невидимые разделители для разделения частей. Эти разделители никогда не видны, но гарантируют, что одна часть не может быть спутана с другой. Например, части ключа ["abc", "def"], ["ab", "cdef"], ["abc", "", "def"] — это все разные ключи.
Ключи чувствительны к регистру и упорядочиваются лексикографически по своим частям. Первая часть является наиболее значимой, а последняя — наименее значимой. Порядок частей определяется как типом, так и значением части.
Порядок частей ключа
Части ключа упорядочиваются лексикографически по их типу, а внутри данного типа — по их значению. Порядок типов следующий:
Uint8Arraystringnumberbigintboolean
Внутри данного типа порядок следующий:
-
Uint8Array: байтовый порядок массива -
string: байтовый порядок UTF-8 кодирования строки -
number: -Infinity < -1.0 < -0.5 < -0.0 < 0.0 < 0.5 < 1.0 < Infinity < NaN -
bigint: математический порядок, наибольшее отрицательное число в первую очередь, наибольшее положительное число в последнюю -
boolean: false < true
Это означает, что часть 1.0 (число) упорядочена перед частью 2.0 (также число), но больше, чем часть 0n (bigint), потому что 1.0 — это число, а 0n — bigint, и порядок типов имеет приоритет над порядком значений в пределах типа.
Примеры ключей
["users", 42, "profile"]; // User with ID 42's profile
["posts", "2023-04-23", "comments"]; // Comments for all posts on 2023-04-23
["products", "electronics", "smartphones", "apple"]; // Apple smartphones in the electronics category
["orders", 1001, "shipping", "tracking"]; // Tracking information for order ID 1001
["files", new Uint8Array([1, 2, 3]), "metadata"]; // Metadata for a file with Uint8Array identifier
["projects", "openai", "tasks", 5]; // Task with ID 5 in the OpenAI project
["events", "2023-03-31", "location", "san_francisco"]; // Events in San Francisco on 2023-03-31
["invoices", 2023, "Q1", "summary"]; // Summary of Q1 invoices for 2023
["teams", "engineering", "members", 1n]; // Member with ID 1n in the engineering team
Универсально уникальные лексикографически сортируемые идентификаторы (ULID)
Порядок частей ключа позволяет записывать ключи, состоящие из временных меток и частей ID, в хронологическом порядке. Как правило, вы можете сгенерировать ключ, используя следующие: Date.now() и crypto.randomUUID():
async function setUser(user) {
await kv.set(["users", Date.now(), crypto.randomUUID()], user);
}
Запустив несколько раз последовательно, это создаст следующие ключи:
["users", 1691377037923, "8c72fa25-40ad-42ce-80b0-44f79bc7a09e"]; // First user
["users", 1691377037924, "8063f20c-8c2e-425e-a5ab-d61e7a717765"]; // Second user
["users", 1691377037925, "35310cea-58ba-4101-b09a-86232bf230b2"]; // Third user
Однако в некоторых случаях представление временной метки и ID в одной части ключа может быть проще. Вы можете использовать универсально уникальный лексикографически сортируемый идентификатор (ULID) для этого. Этот тип идентификатора кодирует метку времени UTC, является лексикографически сортируемым и по умолчанию криптографически случайным:
import { ulid } from "jsr:@std/ulid";
const kv = await Deno.openKv();
async function setUser(user) {
await kv.set(["users", ulid()], user);
}
["users", "01H76YTWK3YBV020S6MP69TBEQ"]; // First user
["users", "01H76YTWK4V82VFET9YTYDQ0NY"]; // Second user
["users", "01H76YTWK5DM1G9TFR0Y5SCZQV"]; // Third user
Кроме того, вы можете генерировать ULID монотонно возрастающие, используя функцию monotonicUlid:
import { monotonicUlid } from "jsr:@std/ulid";
async function setUser(user) {
await kv.set(["users", monotonicUlid()], user);
}
// Strict ordering for the same timestamp by incrementing the least-significant random bit by 1
["users", "01H76YTWK3YBV020S6MP69TBEQ"]; // First user
["users", "01H76YTWK3YBV020S6MP69TBER"]; // Second user
["users", "01H76YTWK3YBV020S6MP69TBES"]; // Third user
Значения
Значения в Deno KV могут быть произвольными значениями JavaScript, совместимыми с алгоритмом структурированного клонирования structured clone algorithm. Это включает:
undefinednullbooleannumberstringbigintUint8ArrayArrayObjectMapSetDateRegExp
Объекты и массивы могут содержать любые из перечисленных типов, включая другие объекты и массивы. Maps и Sets могут содержать любые из перечисленных типов, включая другие Maps и Sets.
Поддерживаются циклические ссылки внутри значений.
Объекты с непримитивным прототипом не поддерживаются (например, экземпляры классов или объекты API веб-браузера). Функции и символы также не могут быть сериализованы.
Deno.KvU64 тип
В дополнение к структурируемым сериализуемым значениям, также поддерживается специальное значение Deno.KvU64. Этот объект представляет 64-битное беззнаковое целое число, представленное как bigint. Он может быть использован с операциями KV sum, min, и max. Он не может быть сохранён внутри объекта или массива. Он должен храниться как значение верхнего уровня.
Он может быть создан с помощью конструктора Deno.KvU64:
const u64 = new Deno.KvU64(42n);
Примеры значений
undefined;
null;
true;
false;
42;
-42.5;
42n;
"hello";
new Uint8Array([1, 2, 3]);
[1, 2, 3];
{ a: 1, b: 2, c: 3 };
new Map([["a", 1], ["b", 2], ["c", 3]]);
new Set([1, 2, 3]);
new Date("2023-04-23");
/abc/;
// Circular references are supported
const a = {};
const b = { a };
a.b = b;
// Deno.KvU64 is supported
new Deno.KvU64(42n);
Временная отметка версии
Все данные в ключевом пространстве Deno KV имеют версию. Каждый раз, когда значение вставляется или изменяется, ему присваивается временная отметка версии. Временные отметки версии монотонно возрастают, не являются последовательными, представляют собой 12-байтовые значения, которые отражают время изменения значения. Временные отметки версии не представляют реального времени, а скорее порядок, в котором значения были изменены.
Поскольку временные отметки версии монотонно возрастают, они могут использоваться для определения, является ли данное значение новее или старее другого значения. Это можно сделать, сравнив временные отметки версии двух значений. Если временная метка версии A больше, чем временная метка версии B, значит, значение A было изменено позднее, чем значение B.
versionstampA > versionstampB;
"000002fa526aaccb0000" > "000002fa526aacc90000"; // true
Все данные, изменённые в рамках одной транзакции, получают одинаковую временную метку версии. Это означает, что если две операции set выполняются в рамках одной атомарной операции, тогда временная метка версии новых значений будет одинаковой.
Временные отметки версии используются для реализации оптимистического управления конкурентностью. Атомарные операции могут содержать проверки, которые гарантируют, что временная метка версии данных, на которых они работают, соответствует временной метке версии, переданной в операцию. Если временная метка версии данных не совпадает с временной меткой версии, переданной в операцию, тогда транзакция будет завершена неудачно, и операция не будет применена.
© 2018–2024 the Deno authors
Licensed under the MIT License.
https://docs.deno.com/deploy/kv/manual/key_space