Skip to content

Commit

Permalink
Add "longer-keys" feature which sets "-DMDB_MAXKEYSIZE=0" when compil…
Browse files Browse the repository at this point in the history
…ing LMDB

By default (and for backwards compatibility) LMDB only allows keys up to 511 bytes in length. If you want larger keys then you need to set "-DMDB_MAXKEYSIZE=0" at compile time.

This limit also applies to values when using the MDB_DUPSORT flag on a database.
  • Loading branch information
tpunder committed May 28, 2024
1 parent 2c90779 commit d925a5a
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 0 deletions.
20 changes: 20 additions & 0 deletions heed/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,26 @@ mdb_idl_logn_14 = ["lmdb-master-sys/mdb_idl_logn_14"]
mdb_idl_logn_15 = ["lmdb-master-sys/mdb_idl_logn_15"]
mdb_idl_logn_16 = ["lmdb-master-sys/mdb_idl_logn_16"]

# Setting this enables you to use keys longer than 511 bytes. The exact limit
# is computed by LMDB at compile time. You can find the exact value by calling
# Env::max_key_size(). This value varies by architecture.
#
# Example max key sizes:
# - Apple M1 (ARM64): 8126 bytes
# - Apple Intel (AMD64): 1982 bytes
# - Linux Intel (AMD64): 1982 bytes
#
# Setting this also enables you to use values larger than 511 bytes when using
# a Database with the DatabaseFlags::DUP_SORT flag.
#
# This builds LMDB with the -DMDB_MAXKEYSIZE=0 option.
#
# Note: If you are moving database files between architectures then your longest
# stored key must fit within the smallest limit of all architectures used. For
# example, if you are moving databases between Apple M1 and Apple Intel
# computers then you need to keep your keys within the smaller 1982 byte limit.
longer-keys = ["lmdb-master-sys/longer-keys"]

[[example]]
name = "rmp-serde"
required-features = ["serde-rmp"]
22 changes: 22 additions & 0 deletions heed/src/database.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2657,4 +2657,26 @@ mod tests {

Ok(())
}

#[test]
#[cfg(feature = "longer-keys")]
fn longer_keys() -> Result<()> {
let dir = tempfile::tempdir()?;
let env = unsafe { EnvOpenOptions::new().open(dir.path())? };
let mut txn = env.write_txn()?;
let db = env.create_database::<Bytes, Bytes>(&mut txn, None)?;

// Try storing a key larger than 511 bytes (the default if MDB_MAXKEYSIZE is not set)
let long_key = b"Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut pharetra sit amet aliquam. Sit amet nisl purus in mollis nunc. Eget egestas purus viverra accumsan in nisl nisi scelerisque. Duis ultricies lacus sed turpis tincidunt. Sem nulla pharetra diam sit. Leo vel orci porta non pulvinar. Erat pellentesque adipiscing commodo elit at imperdiet dui. Suspendisse ultrices gravida dictum fusce ut placerat orci nulla. Diam donec adipiscing tristique risus nec feugiat. In fermentum et sollicitudin ac orci. Ut sem nulla pharetra diam sit amet. Aliquam purus sit amet luctus venenatis lectus. Erat pellentesque adipiscing commodo elit at imperdiet dui accumsan. Urna duis convallis convallis tellus id interdum velit laoreet id. Ac feugiat sed lectus vestibulum mattis ullamcorper velit sed. Tincidunt arcu non sodales neque. Habitant morbi tristique senectus et netus et malesuada fames.";

assert_eq!(db.get(&txn, long_key).unwrap(), None);

db.put(&mut txn, long_key, b"hi").unwrap();
assert_eq!(db.get(&txn, long_key).unwrap(), Some(&b"hi"[..]));

db.put(&mut txn, long_key, b"bye").unwrap();
assert_eq!(db.get(&txn, long_key).unwrap(), Some(&b"bye"[..]));

Ok(())
}
}
8 changes: 8 additions & 0 deletions heed/src/mdb/lmdb_error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,14 @@ pub enum Error {
/// Transaction cannot recover - it must be aborted.
BadTxn,
/// Unsupported size of key/DB name/data, or wrong DUP_FIXED size.
///
/// Common causes of this error:
/// - You tried to store a zero-length key
/// - You tried to store a key longer than the max allowed key (511 bytes by default)
/// - You are using [DUP_SORT](crate::DatabaseFlags::DUP_SORT) and trying to store a
/// value longer than the max allowed key size (511 bytes by default)
///
/// In the last two cases you can enable the `longer-keys` feature to increase the max allowed key size.
BadValSize,
/// The specified DBI was changed unexpectedly.
BadDbi,
Expand Down
20 changes: 20 additions & 0 deletions lmdb-master-sys/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -60,3 +60,23 @@ mdb_idl_logn_13 = []
mdb_idl_logn_14 = []
mdb_idl_logn_15 = []
mdb_idl_logn_16 = []

# Setting this enables you to use keys longer than 511 bytes. The exact limit
# is computed by LMDB at compile time. You can find the exact value by calling
# Env::max_key_size(). This value varies by architecture.
#
# Example max key sizes:
# - Apple M1 (ARM64): 8126 bytes
# - Apple Intel (AMD64): 1982 bytes
# - Linux Intel (AMD64): 1982 bytes
#
# Setting this also enables you to use values larger than 511 bytes when using
# a Database with the DatabaseFlags::DUP_SORT flag.
#
# This builds LMDB with the -DMDB_MAXKEYSIZE=0 option.
#
# Note: If you are moving database files between architectures then your longest
# stored key must fit within the smallest limit of all architectures used. For
# example, if you are moving databases between Apple M1 and Apple Intel
# computers then you need to keep your keys within the smaller 1982 byte limit.
longer-keys = []
4 changes: 4 additions & 0 deletions lmdb-master-sys/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,5 +147,9 @@ fn main() {
builder.flag("-fsanitize=fuzzer-no-link");
}

if cfg!(feature = "longer-keys") {
builder.define("MDB_MAXKEYSIZE", "0");
}

builder.compile("liblmdb.a")
}
11 changes: 11 additions & 0 deletions lmdb-master-sys/tests/simple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,17 @@ fn test_simple(env_path: &str) {

E!(mdb_txn_begin(env, ptr::null_mut(), 0, &mut txn));
E!(mdb_put(txn, dbi, &mut key, &mut data, 0));

if cfg!(feature = "longer-keys") {
// Try storing a key larger than 511 bytes (the default if MDB_MAXKEYSIZE is not set)
let sval = cstr!("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut pharetra sit amet aliquam. Sit amet nisl purus in mollis nunc. Eget egestas purus viverra accumsan in nisl nisi scelerisque. Duis ultricies lacus sed turpis tincidunt. Sem nulla pharetra diam sit. Leo vel orci porta non pulvinar. Erat pellentesque adipiscing commodo elit at imperdiet dui. Suspendisse ultrices gravida dictum fusce ut placerat orci nulla. Diam donec adipiscing tristique risus nec feugiat. In fermentum et sollicitudin ac orci. Ut sem nulla pharetra diam sit amet. Aliquam purus sit amet luctus venenatis lectus. Erat pellentesque adipiscing commodo elit at imperdiet dui accumsan. Urna duis convallis convallis tellus id interdum velit laoreet id. Ac feugiat sed lectus vestibulum mattis ullamcorper velit sed. Tincidunt arcu non sodales neque. Habitant morbi tristique senectus et netus et malesuada fames.").as_ptr() as *mut c_void;

key.mv_size = 952;
key.mv_data = sval;

E!(mdb_put(txn, dbi, &mut key, &mut data, 0));
}

E!(mdb_txn_commit(txn));
}

Expand Down

0 comments on commit d925a5a

Please sign in to comment.