Tradeoffs
Every design picks what to be bad at. This page says what Grepvine chose.
RE2 regular expressions.
Section titled “RE2 regular expressions.”Regex mode uses RE2 syntax, which has no backreferences and no lookaround. In exchange, matching always takes linear time, so no pattern can make a query run away. PCRE syntax isn’t supported.
Patterns need a literal to be fast.
Section titled “Patterns need a literal to be fast.”Grepvine narrows a query to candidate documents using the literal text in its pattern. A pattern with no literal run of at least three bytes, such as \d+, [A-Z]{2,} or ab, can’t be narrowed, so it checks every searchable document. It still returns every match, page by page, but it takes longer on a large index.
To speed such a query up, add a literal (ERROR \d+ rather than \d+), or a metadata filter. A filter narrows the candidates before Grepvine checks any text.
Cold queries.
Section titled “Cold queries.”A query is fastest when its index is in a server’s NVMe cache. The first query after an index has left the cache reads from object storage instead, and takes 15 to 35 times longer. These are measurements of selective queries over the full Wikipedia corpus (19.57 GB):
| Index | One query at a time, p50 / p95 | 20 at a time, p50 / p95 |
|---|---|---|
| Cached on NVMe | 5 / 25 ms | 22 / 51 ms |
| In object storage only | 171 / 543 ms | 480 / 812 ms |
A query that misses the cache fetches only what it needs, and the server then caches more of the index in the background, so the queries that follow run warm. An index nobody queries for a while leaves the cache as other indexes take its place. That is the price of an idle index taking up no machines.
Writes wait for object storage.
Section titled “Writes wait for object storage.”Grepvine acknowledges a write only after it is in object storage, so each write takes longer than a write to memory. Grepvine groups concurrent writes, whole batches included, into shared writes to object storage, so throughput comes from sending many documents at once. Send documents in batches: put_many, putMany and gv upload do this for you. Grepvine targets 50 MiB/s of ingestion with acknowledgment p99 below one second.
Sustained heavy writing can outpace background optimization. When it does, Grepvine first slows writes down. If the backlog keeps growing, it answers 429 with Retry-After. The SDKs and gv wait and retry on their own. Queries stay correct throughout.
Limits.
Section titled “Limits.”| Limit | Value |
|---|---|
| Document | 1 GiB. Searchable when valid UTF-8 and at most 100 MiB. |
| Single upload | Must finish within the 35-second request deadline. |
| Batch | 2,048 documents and 16 MiB of text. |
| Key | 1,024 bytes. |
| Metadata | 64 fields and 64 KiB encoded per document. |
| Pattern | 8 KiB. |
| Filter | 8 KiB. |
| Context lines | 20 before and 20 after each result. |
| Result text | 64 KiB per result, and 4,096 matches. |
| Page size | 1 to 200 results, 50 by default. |
| Page token | Valid for 15 minutes. |
| Index description | 16,384 characters. |
| Index tags | 64 per index. A tag key is 1 to 128 characters; a value is up to 1,024. |