Packages
rocksdb
3.1.1
3.1.2
3.1.1
3.1.0
3.0.0
2.6.2
2.6.1
retired
2.6.0
retired
2.5.0
2.4.1
2.4.0
2.3.0
2.2.0
2.1.0
2.0.0
1.9.0
1.8.0
1.7.0
1.6.0
1.5.1
1.5.0
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.1
1.1.0
1.0.0
0.26.2
0.26.1
0.26.0
0.25.0
0.24.0
0.23.3
0.23.2
0.23.1
0.23.0
0.22.0
0.21.0
0.20.1
0.20.0
0.19.0
0.18.0
0.17.0
0.16.0
0.15.0
0.14.0
0.13.1
0.13.0
0.12.0
0.11.0
0.10.0
0.9.1
0.9.0
0.8.2
0.8.1
0.8.0
0.7.1
0.7.0
0.6.4
0.6.3
0.6.2
0.6.1
0.6.0
RocksDB for Erlang
Current section
Files
Jump to
Current section
Files
guides/ttl.md
# Time-to-Live (TTL) Support
RocksDB supports automatic expiration of key-value pairs through Time-to-Live (TTL). Keys inserted into a TTL-enabled database will be automatically deleted after a specified duration.
## How TTL Works
When you open a database with TTL enabled:
1. **Timestamp Suffixing**: A 32-bit timestamp (creation time) is automatically appended to each value during `put` operations
2. **Expiration Check**: During compaction, RocksDB checks if `timestamp + ttl < current_time`
3. **Lazy Deletion**: Expired keys are removed only during compaction (not immediately upon expiration)
## Important Behaviors
- **Non-Strict Guarantees**: Keys are guaranteed to exist for at least TTL seconds, but may persist longer until compaction runs
- **Stale Reads**: `get` and iterator operations may return expired entries if compaction hasn't run yet
- **Read-Only Mode**: Opens the database without triggering compactions, so expired keys won't be removed
- **Variable TTL**: Different TTL values can be used across different database opens
## Basic Usage
### Opening a Database with TTL
```erlang
%% Open a database with 1 hour (3600 seconds) TTL
{ok, Db} = rocksdb:open_with_ttl(
"my_ttl_db",
[{create_if_missing, true}],
3600, % TTL in seconds
false % read_only flag
).
%% All standard operations work normally
ok = rocksdb:put(Db, <<"key1">>, <<"value1">>, []),
{ok, <<"value1">>} = rocksdb:get(Db, <<"key1">>, []),
%% Close when done
ok = rocksdb:close(Db).
```
### TTL Expiration Example
```erlang
%% Open with 1 second TTL for demonstration
{ok, Db} = rocksdb:open_with_ttl("ttl_test", [{create_if_missing, true}], 1, false),
%% Insert a key
ok = rocksdb:put(Db, <<"temp_key">>, <<"temp_value">>, []),
%% Key exists immediately
{ok, <<"temp_value">>} = rocksdb:get(Db, <<"temp_key">>, []),
%% Wait for TTL to expire
timer:sleep(2000),
%% Key may still exist (compaction hasn't run)
%% Force compaction to trigger cleanup
ok = rocksdb:compact_range(Db, <<"a">>, <<"z">>, []),
%% Now the key is gone
not_found = rocksdb:get(Db, <<"temp_key">>, []),
ok = rocksdb:close(Db).
```
### Read-Only Mode
```erlang
%% Open in read-only mode - no compactions will run
{ok, Db} = rocksdb:open_with_ttl("my_ttl_db", [], 3600, true),
%% Can read but not write
{ok, Value} = rocksdb:get(Db, <<"key">>, []),
%% Note: Expired keys won't be cleaned up in read-only mode
ok = rocksdb:close(Db).
```
## Column Family Support
### Opening with Multiple Column Families (each with its own TTL)
```erlang
%% Open with column families, each having a different TTL
{ok, Db, [DefaultCF, SessionsCF, CacheCF]} = rocksdb:open_with_ttl_cf(
"multi_ttl_db",
[{create_if_missing, true}],
[
{"default", [], 86400}, % 24 hours
{"sessions", [], 3600}, % 1 hour
{"cache", [], 300} % 5 minutes
],
false
).
%% Write to different column families
ok = rocksdb:put(Db, DefaultCF, <<"user:1">>, <<"data">>, []),
ok = rocksdb:put(Db, SessionsCF, <<"sess:abc">>, <<"token">>, []),
ok = rocksdb:put(Db, CacheCF, <<"cache:xyz">>, <<"cached">>, []),
ok = rocksdb:close(Db).
```
### Creating a Column Family with TTL
```erlang
%% First open a TTL database
{ok, Db} = rocksdb:open_with_ttl("my_db", [{create_if_missing, true}], 3600, false),
%% Create a new column family with a specific TTL
{ok, NewCF} = rocksdb:create_column_family_with_ttl(
Db,
"temp_data",
[], % Column family options
600 % 10 minute TTL
),
%% Use the new column family
ok = rocksdb:put(Db, NewCF, <<"key">>, <<"value">>, []),
ok = rocksdb:close(Db).
```
### Getting and Setting TTL Dynamically
```erlang
{ok, Db, [DefaultCF]} = rocksdb:open_with_ttl_cf(
"my_db",
[{create_if_missing, true}],
[{"default", [], 3600}],
false
),
%% Get current TTL for a column family
{ok, CurrentTTL} = rocksdb:get_ttl(Db, DefaultCF),
io:format("Current TTL: ~p seconds~n", [CurrentTTL]),
%% Set a new TTL for the column family
ok = rocksdb:set_ttl(Db, DefaultCF, 7200), % Change to 2 hours
%% Set default TTL for the database
ok = rocksdb:set_ttl(Db, 1800), % 30 minutes
ok = rocksdb:close(Db).
```
## Alternative: Compaction Filter TTL
For more control over TTL behavior, you can use compaction filters with timestamp-based rules. This is useful when your keys contain embedded timestamps.
```erlang
%% TTL based on timestamp embedded in key
%% Format: {ttl_from_key, Offset, Length, TTLSeconds}
{ok, Db} = rocksdb:open("my_db", [
{create_if_missing, true},
{compaction_filter, #{
rules => [{ttl_from_key, 0, 8, 3600}] % Read 8 bytes at offset 0 as timestamp
}}
]),
%% Create keys with embedded timestamps
Timestamp = erlang:system_time(second),
Key = <<Timestamp:64/big, "mydata">>,
ok = rocksdb:put(Db, Key, <<"value">>, []),
ok = rocksdb:close(Db).
```
See the [Compaction Filters Guide](compaction_filters.md) for more details.
## API Reference
### rocksdb:open_with_ttl/4
```erlang
-spec open_with_ttl(Name, DBOpts, TTL, ReadOnly) ->
{ok, db_handle()} | {error, any()}.
```
Opens a database with TTL support.
| Parameter | Type | Description |
|-----------|------|-------------|
| Name | `file:filename_all()` | Path to the database directory |
| DBOpts | `db_options()` | Database options |
| TTL | `integer()` | Time-to-live in seconds (0 or negative = infinity) |
| ReadOnly | `boolean()` | If true, opens in read-only mode |
### rocksdb:open_with_ttl_cf/4
```erlang
-spec open_with_ttl_cf(Name, DBOpts, CFDescriptors, ReadOnly) ->
{ok, db_handle(), [cf_handle()]} | {error, any()}.
```
Opens a database with multiple column families, each with its own TTL.
| Parameter | Type | Description |
|-----------|------|-------------|
| Name | `file:filename_all()` | Path to the database directory |
| DBOpts | `db_options()` | Database options |
| CFDescriptors | `[{Name, CFOpts, TTL}]` | List of column family descriptors with TTLs |
| ReadOnly | `boolean()` | If true, opens in read-only mode |
### rocksdb:create_column_family_with_ttl/4
```erlang
-spec create_column_family_with_ttl(DBHandle, Name, CFOpts, TTL) ->
{ok, cf_handle()} | {error, any()}.
```
Creates a new column family with a specific TTL.
### rocksdb:get_ttl/2
```erlang
-spec get_ttl(DBHandle, CFHandle) -> {ok, integer()} | {error, any()}.
```
Gets the current TTL for a column family.
### rocksdb:set_ttl/2
```erlang
-spec set_ttl(DBHandle, TTL) -> ok | {error, any()}.
```
Sets the default TTL for the database.
### rocksdb:set_ttl/3
```erlang
-spec set_ttl(DBHandle, CFHandle, TTL) -> ok | {error, any()}.
```
Sets the TTL for a specific column family.
## Best Practices
1. **Trigger Compaction for Immediate Cleanup**: If you need expired keys removed immediately, call `rocksdb:compact_range/4`
2. **Use Appropriate TTL Values**: Very short TTLs (< 1 second) may cause excessive data churn
3. **Don't Mix TTL and Non-TTL Opens**: Always use `open_with_ttl` functions to access a TTL database. Using regular `open` will return corrupted values (with timestamp suffix)
4. **Consider Column Family TTLs**: Use different TTLs for different data types by organizing them into column families
5. **Monitor Disk Usage**: Expired keys consume disk space until compaction runs
## Warnings
- **Value Corruption**: Opening a TTL database with regular `rocksdb:open` will return corrupted values because of the timestamp suffix
- **Short TTLs**: Using very small TTL values may delete your entire database quickly
- **No Immediate Expiration**: TTL expiration is lazy - keys persist until compaction