← 返回日报
略读 预计 5 分钟

Lightning Memory-Mapped Database Manager (LMDB) 1.0

摘要

LMDB 是基于 B+ 树的数据库管理库,模仿 BerkeleyDB API 简化设计。整个数据库暴露在内存映射中,所有数据获取直接从映射内存返回,避免 malloc 和 memcpy。库非常简单,无需自身页面缓存层,性能极高、内存效率极高。支持完全事务性,具有完整 ACID 语义;内存映射为只读时,应用代码 stray pointer 写入无法破坏数据库完整性。库完全线程感知,支持多进程和线程并发读写访问。数据页面采用 copy-on-write 策略,无活跃数据页面被覆盖,提供抗损坏能力,无需系统崩溃后特殊恢复。写入完全序列化,仅一个写事务可同时激活,保证写事务永不死锁。数据库多版本,读者无锁运行;写事务不阻塞读者,读者不阻塞写事务。与其他使用 WAL 或仅追加写入的机制不同,LMDB 无需运行中维护。两者均需定期 checkpointing 和 / 或 compaction,否则文件无限增长。LMDB 在数据库内跟踪空闲页面,并重用它们进行新写操作,正常使用下数据库大小不会无限增长。内存映射可用于只读或读写模式。默认只读模式提供总抗损坏能力。使用读写模式提供更高写性能,但增加应用代码通过指针静默损坏数据库的风险。第一次使用事务性嵌入式键值存储时,可参考 Getting Started 页面。存在注意事项:锁文件和 BSD 系统信号量问题;固定器和重用器检查;配置常预留大量未使用地址空间和文件大小供未来增长;默认在 0.9.10 前数据文件未使用部分可能接收其他代码释放的垃圾内存(使用 MDB WRITEMAP 标志时不发生);线程一次只能使用一个事务(MDB NOTLS 标志可改写);使用打开它的进程的环境,不在 fork 后使用;同一进程不可同时打开两次数据库;避免长生命周期事务;避免挂起带活跃事务的进程;多个进程并发使用时避免中止带活跃事务的进程;不要在远程文件系统上使用数据库;打开数据库时如果另一进程同时打开或关闭可能失败。作者为 Howard Chu,Symas Corporation。版权 2011-2026 Howard Chu,Symas Corp。基于 Martin Hedenfalk 2009-2010 年 btree.c 代码。

荐读理由

LMDB 将数据库完全映射到内存,无 malloc 与 memcpy 就能直接返回数据,零页缓存且 ACID 全事务,适合 AI 工程嵌入式 KV 场景直接迁移使用

原文

LMDB 1.0

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages

Lightning Memory-Mapped Database Manager (LMDB)

Introduction

LMDB is a Btree-based database management library modeled loosely on the BerkeleyDB API, but much simplified. The entire database is exposed in a memory map, and all data fetches return data directly from the mapped memory, so no malloc's or memcpy's occur during data fetches. As such, the library is extremely simple because it requires no page caching layer of its own, and it is extremely high performance and memory-efficient. It is also fully transactional with full ACID semantics, and when the memory map is read-only, the database integrity cannot be corrupted by stray pointer writes from application code.

Note: This is the documentation for LMDB 1.0. The docs for LMDB 0.9 are archived here.

See Upgrading From Release 0.9 if you used LMDB 0.9 previously.

The library is fully thread-aware and supports concurrent read/write access from multiple processes and threads. Data pages use a copy-on- write strategy so no active data pages are ever overwritten, which also provides resistance to corruption and eliminates the need of any special recovery procedures after a system crash. Writes are fully serialized; only one write transaction may be active at a time, which guarantees that writers can never deadlock. The database structure is multi-versioned so readers run with no locks; writers cannot block readers, and readers don't block writers.

Unlike other well-known database mechanisms which use either write-ahead transaction logs or append-only data writes, LMDB requires no maintenance during operation. Both write-ahead loggers and append-only databases require periodic checkpointing and/or compaction of their log or database files otherwise they grow without bound. LMDB tracks free pages within the database and re-uses them for new write operations, so the database size does not grow without bound in normal use.

The memory map can be used as a read-only or read-write map. It is read-only by default as this provides total immunity to corruption. Using read-write mode offers much higher write performance, but adds the possibility for stray application writes thru pointers to silently corrupt the database. Of course if your application code is known to be bug-free (...) then this is not an issue.

If this is your first time using a transactional embedded key/value store, you may find the Getting Started page to be helpful.

Caveats

Troubleshooting the lock file, plus semaphores on BSD systems:

  • A broken lockfile can cause sync issues. Stale reader transactions left behind by an aborted program cause further writes to grow the database quickly, and stale locks can block further operation.

  • Fix: Check for stale readers periodically, using the mdb_reader_check function or the mdb_stat tool. Stale writers will be cleared automatically on most systems:

    • Windows - automatic

    • BSD, systems using SysV semaphores - automatic

    • Linux, systems using POSIX mutexes with Robust option - automatic Otherwise just make all programs using the database close it; the lockfile is always reset on first open of the environment.

  • On BSD systems or others configured with MDB_USE_SYSV_SEM or MDB_USE_POSIX_SEM, startup can fail due to semaphores owned by another userid.

  • Fix: Open and close the database as the user which owns the semaphores (likely last user) or as root, while no other process is using the database.

Restrictions/caveats (in addition to those listed for some functions):

  • Only the database owner should normally use the database on BSD systems or when otherwise configured with MDB_USE_POSIX_SEM. Multiple users can cause startup to fail later, as noted above.

  • There is normally no pure read-only mode, since readers need write access to locks and lock file. Exceptions: On read-only filesystems or with the MDB_NOLOCK flag described under mdb_env_open().

  • An LMDB configuration will often reserve considerable unused memory address space and maybe file size for future growth. This does not use actual memory or disk space, but users may need to understand the difference so they won't be scared off.

  • By default, in versions before 0.9.10, unused portions of the data file might receive garbage data from memory freed by other code. (This does not happen when using the MDB_WRITEMAP flag.) As of 0.9.10 the default behavior is to initialize such memory before writing to the data file. Since there may be a slight performance cost due to this initialization, applications may disable it using the MDB_NOMEMINIT flag. Applications handling sensitive data which must not be written should not use this flag. This flag is irrelevant when using MDB_WRITEMAP.

  • A thread can only use one transaction at a time, plus any child transactions. Each transaction belongs to one thread. See below. The MDB_NOTLS flag changes this for read-only transactions.

  • Use an MDB_env* in the process which opened it, not after fork().

  • Do not have open an LMDB database twice in the same process at the same time. Not even from a plain open() call - close()ing it breaks fcntl() advisory locking. (It is OK to reopen it after fork() - exec*(), since the lockfile has FD_CLOEXEC set.)

  • Avoid long-lived transactions. Read transactions prevent reuse of pages freed by newer write transactions, thus the database can grow quickly. Write transactions prevent other write transactions, since writes are serialized.

  • Avoid suspending a process with active transactions. These would then be "long-lived" as above. Also read transactions suspended when writers commit could sometimes see wrong data.

...when several processes can use a database concurrently:

  • Avoid aborting a process with an active transaction. The transaction becomes "long-lived" as above until a check for stale readers is performed or the lockfile is reset, since the process may not remove it from the lockfile.

  • This does not apply to write transactions if the system clears stale writers, see above.

  • If you do that anyway, do a periodic check for stale readers. Or close the environment once in a while, so the lockfile can get reset.

  • Do not use LMDB databases on remote filesystems, even between processes on the same host. This breaks flock() on some OSes, possibly memory map sync, and certainly sync between programs on different hosts.

  • Opening a database can fail if another process is opening or closing it at exactly the same time.

Author

Howard Chu, Symas Corporation.

Copyright

Copyright 2011-2026 Howard Chu, Symas Corp. All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted only as authorized by the OpenLDAP Public License.

A copy of this license is available in the file LICENSE in the top-level directory of the distribution or, alternatively, at http://www.OpenLDAP.org/license.html.

Derived From:

This code is derived from btree.c written by Martin Hedenfalk.

Copyright (c) 2009, 2010 Martin Hedenfalk marti.nosp@m.n@bz.nosp@m.ero.s.nosp@m.e

Permission to use, copy, modify, and distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies.

THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.


Generated on Tue Jun 30 2026 20:10:10 for LMDB by doxygen 1.8.2-20120930

Hacker News · 5 赞 · 1 评 讨论 → 阅读原文 →

这条对你有帮助吗?