Skip to main content

ZMap

Ordered Key-Value Store Backed by FoundationDB

Kronotop introduces a novel data structure called ZMap, which serves as a Redis-compatible proxy over FoundationDB’s transactional key-value API.

Under the hood, ZMap leverages FoundationDB’s core data model — a highly reliable, ordered key-value store.
Also referred to as an ordered associative array or dictionary, this structure is composed of unique keys arranged in lexicographical order, each mapped to a corresponding value.

By exposing this powerful model through the familiar RESP protocol, ZMap allows developers to interact with FoundationDB in a simple, efficient, and idiomatic way — without requiring deep knowledge of FoundationDB's lower-level API.

ZMap forms the foundation for building richer abstractions and serves as a building block for higher-level features like namespaces, Buckets, and transactional queries through MQL.

See the Data Modeling section on FoundationDB documents.

One-Off Transactions

Kronotop will create a new transaction and automatically commit changes to the database for the ad-hoc commands.

In other terms, you do not need to do this for every command:

127.0.0.1:5484> BEGIN
OK
127.0.0.1:5484> ZSET mykey "Hello"
OK
127.0.0.1:5484> COMMIT
OK

The one-off transaction feature is especially useful for running commands in CLI.

ZMap and Namespaces

A namespace prefixes all data stored in a ZMap. The current namespace can be inspected by running the following command:

127.0.0.1:5484> NAMESPACE CURRENT
global

global is the default namespace. Namespaces create isolation between data structures. This is how it works for ZMap

127.0.0.1:5484> NAMESPACE CURRENT
global
127.0.0.1:5484> ZSET mykey "Hello"
OK
127.0.0.1:5484> ZGET mykey
"Hello"
127.0.0.1:5484> NAMESPACE CREATE global.child-namespace
OK
127.0.0.1:5484> NAMESPACE USE global.child-namespace
OK
127.0.0.1:5484> ZGET mykey
(nil)

See the Namespaces section for further information.

Commands

ZSET

ZSET sets the value for a given key. This will not affect the database until COMMIT is called.

Syntax

ZSET key value

Example:

127.0.0.1:5484> ZSET mykey "Hello"
OK

ZGET

ZGET gets a value from the database. The call will return nil if the key is not present in the database.

Syntax

ZGET key

Example:

127.0.0.1:5484> ZGET mykey
"Hello"

ZGETKEY

ZGETKEY returns the key referenced by the specified KeySelector.

The default key selector is FIRST_GREATER_OR_EQUAL. KEY_SELECTOR portion of the command is optional.

Syntax

ZGETKEY key value [KEY_SELECTOR selector]

Available key selectors:

  • FIRST_GREATER_OR_EQUAL,
  • FIRST_GREATER_THAN,
  • LAST_LESS_THAN,
  • LAST_LESS_OR_EQUAL

Example:

127.0.0.1:5484> zset key-0 value-0
OK
127.0.0.1:5484> zset key-1 value-1
OK
127.0.0.1:5484> zset key-2 value-2
OK
127.0.0.1:5484> zset key-3 value-3
OK
127.0.0.1:5484> ZGETKEY key-0 KEY_SELECTOR FIRST_GREATER_THAN
"key-1"

ZGETRANGE

ZGETRANGE gets an ordered range of keys and values from the database. The begin and end keys can be specified by key selectors, with the begin BEGIN_KEY_SELECTOR inclusive and the end END_KEY_SELECTOR exclusive.

Syntax

ZGETRANGE key [key ...] [BEGIN_KEY_SELECTOR selector] [END_KEY_SELECTOR selector] [LIMIT limit] [REVERSE]

The default BEGIN_KEY_SELECTOR is FIRST_GREATER_OR_EQUAL. The default END_KEY_SELECTOR is FIRST_GREATER_THAN.

Available key selectors:

  • FIRST_GREATER_OR_EQUAL,
  • FIRST_GREATER_THAN,
  • LAST_LESS_THAN,
  • LAST_LESS_OR_EQUAL

The key selector section of this command is optional.

Example:*

127.0.0.1:5484> ZGETRANGE key-0 key-3
1) 1) "key-0"
2) "value-0"
2) 1) "key-1"
2) "value-1"
3) 1) "key-2"
2) "value-2"

With the optional LIMIT argument:

127.0.0.1:5484> ZGETRANGE key-0 key-5 LIMIT 3
1) 1) "key-0"
2) "value-0"
2) 1) "key-1"
2) "value-1"
3) 1) "key-2"
2) "value-2"

With LIMIT and REVERSE arguments:

127.0.0.1:5484> ZGETRANGE key-0 key-5 LIMIT 3 REVERSE
1) 1) "key-4"
2) "value-4"
2) 1) "key-3"
2) "value-3"
3) 1) "key-2"
2) "value-2"

The REVERSE argument is also optional.

Range from beginning to end, get an ordered set or key/value pairs:

127.0.0.1:5484> ZGETRANGE * *
1) 1) "key-0"
2) "value-0"
2) 1) "key-1"
2) "value-1"
3) 1) "key-2"
2) "value-2"
4) 1) "key-3"
2) "value-3"
5) 1) "key-4"
2) "value-4"
6) 1) "key-5"
2) "value-5"
7) 1) "key-6"
2) "value-6"

Explicitly using key selectors, please note that you can use the key selectors individually.

127.0.0.1:5484> ZGETRANGE key-2 key-5 BEGIN_KEY_SELECTOR FIRST_GREATER_THAN
1) 1) "key-3"
2) "value-3"
2) 1) "key-4"
2) "value-4"

ZGETRANGESIZE

ZGETRANGESIZE gets an estimate for the number of bytes stored in the given range.

Syntax

ZGETRANGESIZE begin-key end-key

Example

127.0.0.1:5484> zgetrangesize key-0 key-9
(integer) 0

FoundationDB says:

Note: the estimated size is calculated based on the sampling done by FDB server. The sampling algorithm works roughly in this way: the larger the key-value pair is, the more likely it would be sampled and the more accurate its sampled size would be. And due to that reason, it is recommended to use this API to query against large ranges for accuracy considerations. For a rough reference, if the returned size is larger than 3MB, one can consider the size to be accurate.

ZMUTATE

ZMUTATE runs an atomic operation on the given key.

Syntax

ZMUTATE key value mutation-type

Valid Mutation Types

  • ADD: Performs an addition of little-endian integers.
  • APPEND_IF_FITS: Appends param to the end of the existing value already in the database at the given key (or creates the key and sets the value to param if the key is empty).
  • BIT_AND: Performs a bitwise and operation.
  • BIT_OR: Performs a bitwise or operation.
  • BIT_XOR: Performs a bitwise xor operation.
  • BYTE_MAX: Performs lexicographic comparison of byte strings.
  • BYTE_MIN: Performs lexicographic comparison of byte strings.
  • COMPARE_AND_CLEAR: Performs an atomic compare and clear operation.
  • MAX: Performs a little-endian comparison of byte strings.
  • MIN: Performs a little-endian comparison of byte strings.
  • SET_VERSIONSTAMPED_KEY: Transforms key using a versionstamp for the transaction.
  • SET_VERSIONSTAMPED_VALUE: Transforms param using a versionstamp for the transaction.

Example:

127.0.0.1:5484> ZSET key-0 value-0
OK
127.0.0.1:5484> ZMUTATE key-0 value COMPARE_AND_CLEAR
OK
127.0.0.1:5484> ZGET key-0
"value-0"
127.0.0.1:5484> ZMUTATE key-0 value-0 COMPARE_AND_CLEAR
OK
127.0.0.1:5484> ZGET key-0
(nil)

ZDEL

ZDEL clears a given key from the database. This will not affect the database until COMMIT is called.

Syntax

ZDEL key

Example:

127.0.0.1:5484> ZDEL mykey
OK

ZDELRANGE

ZDELRANGE clears the keys in the given range. The begin is inclusive, end is exclusive.

Syntax

ZDELRANGE begin-key end-key

Example:

127.0.0.1:5484> ZDELRANGE key-1 key-4
OK
127.0.0.1:5484> ZGETRANGE * *
1) 1) "key-0"
2) "value-0"
2) 1) "key-4"
2) "value-4"
3) 1) "key-5"
2) "value-5"
4) 1) "key-6"
2) "value-6"

Using * asterisk character to set a boundary:

Wipe out all keys in the current namespace:

127.0.0.1:5484> ZDELRANGE * *
OK
127.0.0.1:5484> ZGETRANGE * *
(empty array)

Clear all keys from the beginning to key-3:

127.0.0.1:5484> ZDELRANGE * key-3
OK
127.0.0.1:5484> ZGETRANGE * *
1) 1) "key-3"
2) "value-3"
2) 1) "key-4"
2) "value-4"
3) 1) "key-5"
2) "value-5"

Clear all keys from key-3 to the end of the range:

127.0.0.1:5484> ZDELRANGE key-3 *
OK
127.0.0.1:5484> ZGETRANGE * *
1) 1) "key-0"
2) "value-0"
2) 1) "key-1"
2) "value-1"
3) 1) "key-2"
2) "value-2"