Pre-1.0 hoardDB is pre-1.0. Expect breaking changes.
Limits
Every size and count that hoardDB enforces, with its default, how to change it and what you see when you reach it. This page is the numbers; Limitations is the list of things hoardDB does not do, and explains the reasoning behind several of these.
A limit that an operator can change is a setting of one node. A write that reaches a replica is not checked against the replica’s own value, so keep these settings the same on every node of a cluster.
How big can one thing be
| What | Default | You can set | Setting | When you reach it |
|---|---|---|---|---|
| A document | 24 MiB (25,165,824 bytes) | 4 KiB to 30 MiB (4,096 to 31,457,280 bytes) | HOARDDB_MAX_DOCUMENT_BYTES, storage.max_document_bytes | The write is refused; an update that would grow a document past it is refused and leaves the document unchanged |
| A blob | 16 MiB (16,777,216 bytes) | 1 byte to 31.9 MiB (33,488,896 bytes) | HOARDDB_MAX_BLOB_BYTES, storage.max_blob_bytes | The write is refused |
| One protocol frame | 32 MiB (33,554,432 bytes) | fixed | none | The server closes the connection and logs closing connection: bad frame with frame length N exceeds maximum 33554432 |
| What one query may hold in memory | 16 MiB | 1 MiB to 24 MiB (a smaller value is raised to 1 MiB, with a warning) | HOARDDB_QUERY_MAX_RESULT_BYTES, query.max_result_bytes | The query is refused with RESULT_TOO_LARGE |
| One atomic batch | 15% of the memtable (20 MB at 128 MiB) | follows storage.memtable_mb | HOARDDB_MEMTABLE_MB | The whole batch is refused and nothing of it is written |
| One statement typed in the CLI | 64 KiB per line | fixed | none | CLI error: read input: bufio.Scanner: token too long |
| A bucket’s size, or the documents in it | no limit | The disk is the bound |
Why the document and blob limits are not 32 MiB. Everything a client sends, and the copy a node sends to a replica, travels in one frame of at most 32 MiB, and the frame also carries the key, the bucket name and the request’s envelope. The ceilings leave room for that: a document tops out at 30 MiB, and a blob at 32 MiB less 64 KiB. A value outside the range you can set stops the server from starting, with a message naming the setting and the range; it is never quietly lowered.
What the refusals say. They state the size you sent, the limit this server is running with, the setting that changes it and what to do instead:
Blob "videos/intro.mp4" is 5.0 GiB; this server's limit is 16 MiB
(storage.max_blob_bytes, maximum 31.9 MiB). For larger files, keep the file on
your own storage and store a pointer document — see "Large file stores" in the
docs.
<label> is <size>; this server's limit is <limit> per document
(storage.max_document_bytes, maximum 30 MiB).
The CLI refuses a blob larger than the 31.9 MiB ceiling before it sends any of it, since no server would accept it.
What to do instead of raising a limit.
- A list that keeps growing belongs in a nested store field, whose elements are stored separately and do not count towards the parent document.
- A file that is large belongs on storage you run, with a pointer document in hoardDB. Large file stores is the pattern.
- A bulk load that is refused for its size is a bulk load that should be split:
hoardDB-cli ingesthalves a refused batch and retries, so a file of any size loads. See Load a file.
How many buckets
A bucket is a key range in the one store a node keeps for all its buckets. It costs no file, no file descriptor, no memory mapping and no goroutine of its own, and it adds one small entry to the node’s in-memory catalog. Adding a bucket is adding keys, not opening anything.
The figure to plan around is thousands of buckets per node. hoardDB is built for many small buckets, one per user or per post, and it does not publish a larger number until it has measured one on this layout. Higher counts may work on your hardware; they are not a promise. What a bucket costs, and how to see how many a node serves, is in Is this node full?.
hoardDB keeps no metric per bucket. A series per bucket is not viable at these
counts, so the metrics are totals for the node, and per-bucket detail is a
command you run (describe bucket, stats).
The memtable
The memtable is the write buffer in front of the node’s one store. It is a per-node setting: every bucket shares it, so it does not grow with the number of buckets.
A new node picks its size once, from the memory it is allowed (its container or cgroup limit, or the machine’s RAM), and keeps it on every restart:
| Memory limit | Memtable chosen | Largest atomic batch (15%) | Memory a heavy write burst can reach |
|---|---|---|---|
| below 3.5 GiB | 32 MiB | about 5 MB (5,033,164 bytes) | about 460 MB |
| 3.5 GiB to below 7 GiB | 64 MiB | about 10 MB (10,066,329 bytes) | about 725 MB |
| 7 GiB and above | 128 MiB | about 20 MB (20,132,659 bytes) | about 1.25 GB |
The automatic choice never goes above 128 MiB. The last column is a prediction for one client loading in batches, about 200 MB plus 8.2 MB for every MiB of memtable; many concurrent writers need more.
To choose it yourself, set storage.memtable_mb (HOARDDB_MEMTABLE_MB) to
a value from 32 to 1024 MiB. Sizes of 256 MiB and above are only ever set this
way. A value outside the range stops the server at start:
storage.memtable_mb is 8, below the minimum of 32. The store's largest atomic
batch is 15% of the memtable, and under 32 MiB it drops below 5 MB, which the
ingest batch budget and batch splitting assume. Set storage.memtable_mb (or
HOARDDB_MEMTABLE_MB) to a value from 32 to 1024, or remove it to run at the size
this node's store chose at its first start
A bigger memtable stalls writes less and holds up to three of them in memory, each needing about 1.3 times its size, so 1024 MiB is already about 3.9 GB. It is fixed at start. A node that crashed at a larger size cannot be opened at a smaller one until it has been started once at the old size and stopped cleanly. Configuration shows how to read the size a node chose, and why.
Connections and requests
| What | Default | Range | Setting |
|---|---|---|---|
| Concurrent client connections per node | 1,000 | HOARDDB_MAX_CONNS | |
| Concurrent connections from one address | 64 | 0 turns the cap off | HOARDDB_TCP_MAX_CONNS_PER_IP |
| Connections kept for other nodes | 64 | HOARDDB_MAX_PEER_CONNS | |
| Idle time before a connection is closed | 300 seconds | HOARDDB_TCP_IDLE_TIMEOUT | |
| Time to read one frame | 30 seconds | HOARDDB_TCP_FRAME_TIMEOUT | |
| Requests a client may have in flight on one connection | 4 | 1 to 64 | HOARDDB_TCP_PIPELINE_FRAMES |
| Bytes of those requests | 1 MiB | 1 MiB to 16 MiB (a smaller value is raised to 1 MiB, with a warning) | HOARDDB_TCP_PIPELINE_BYTES |
| Queries running at once | twice the CPU count | 4 to 256 | HOARDDB_QUERY_CONCURRENCY |
| Failed logins in a row before an address is refused | 20 | 0 turns the limit off | HOARDDB_TCP_AUTH_MAX_FAILS |
| Shortest user password | 12 characters | HOARDDB_PASSWORD_MIN_LENGTH |
The client budget (HOARDDB_MAX_CONNS) and the node-to-node budget are
separate, so a flood of clients cannot starve replication. A connection carries
one request at a time unless the client reads ahead within the window above;
a client that wants concurrency opens another connection. A query past the
concurrency limit waits; it is not refused.
A value outside a range with a stated clamp is brought to the nearest end of it when the server loads its configuration. The sizes in the first table are the other kind: outside their range, the server refuses to start.
Checking a limit against your data
Before you rely on a limit, try it at its edge on your own data. The sizes and counts above are what the build enforces, and they were read from its configuration, not measured on your workload: your hardware, your kernel’s file-descriptor and memory-mapping limits, and the shape of your documents decide where a node becomes slow before any of them is reached. Is this node full? lists the resources that bind first and what to do about each.
Source: docs/user/limits.md in the repository.