Skip to main content

Overview

A Comparator defines the total order across keys in RocksDB. Custom comparators allow you to implement application-specific key ordering beyond simple lexicographic byte comparison.
Changing comparators after creating a database requires careful migration. A database created with one comparator cannot be safely accessed with a different comparator.

The Comparator Interface

The Comparator class from comparator.h:44 provides the core abstraction for key ordering:

Key Methods

Compare() - The core comparison function. Must be:
  • Thread-safe (may be called concurrently from multiple threads)
  • Consistent (same inputs always produce same output)
  • Transitive (if a < b and b < c, then a < c)
Name() - Returns a unique identifier. RocksDB uses this to detect comparator mismatches:
Names starting with “rocksdb.” are reserved. Use a custom prefix for your comparators.
FindShortestSeparator() - Optional optimization to reduce index block size. Can be left as no-op. FindShortSuccessor() - Optional optimization for index blocks. Can be left as no-op.

Built-in Comparators

RocksDB provides several built-in comparators defined in comparator.h:187-208:

BytewiseComparator

Uses lexicographic ordering on unsigned bytes. Empty string comes before all other strings.

ReverseBytewiseComparator

Reverse ordering of BytewiseComparator.

User-Defined Timestamp Comparators

For user-defined timestamps (UDT), where newer timestamps (larger values) come first for the same user key.

Implementing a Custom Comparator

Example: Integer Key Comparator

Using Your Custom Comparator

The comparator object must outlive the database. Keep it in scope or use a singleton pattern.

User-Defined Timestamps

Starting from RocksDB 7.0, you can associate timestamps with keys. The Comparator constructor accepts a timestamp size:

Timestamp Handling

When timestamps are enabled (timestamp_size_ > 0):

Timestamp Utilities

From comparator.h:216-234:

Advanced Features

Key Equivalence

Return false if your comparator ensures different byte sequences are always different keys. This enables optimizations like DataBlockHashIndex.

Same-Length Successor Detection

Used for auto_prefix_mode optimization. Return true if t is the immediate successor of s with the same length.

Best Practices

Thread Safety: Comparators must be thread-safe. All methods may be called concurrently from multiple threads.
Exception Safety: Exceptions must NOT propagate out of comparator methods. This can cause undefined behavior including data loss.

Performance Considerations

  1. Optimize Compare() - This is called very frequently in hot paths
  2. Avoid memory allocations - Use stack variables when possible
  3. Keep it simple - Complex comparisons add overhead to all operations

Migration

Changing comparators requires careful planning:
  1. Export data with old comparator
  2. Create new database with new comparator
  3. Import data into new database
There is no automatic migration path.

Filter Integration

If your comparator ignores parts of keys (e.g., suffixes), you must provide a compatible FilterPolicy. The default Bloom filter (NewBloomFilterPolicy()) will not work correctly.
From filter_policy.h:159-165:
If the comparator ignores trailing spaces, it would be incorrect to use a FilterPolicy (like NewBloomFilterPolicy) that does not ignore trailing spaces in keys.

Common Patterns

Composite Keys

Reverse Timestamp Ordering

See Also