log文件在LevelDb中的主要作用是系统故障恢复时,能够保证不会丢失数据。
记录写入内存的Memtable之前,会先写入Log文件,这样即使系统发生故障,Memtable中的数据没有来得及Dump到磁盘的SSTable文件,LevelDB也可以根据log文件恢复内存的Memtable数据结构内容,不会造成系统丢失数据.
看下图两个数据库:log文件并不是一成不变的,记录的相当于是最新的操作。
猜测原因:我进行了getAll查询操作,日志变为空,什么数据都没有。

进行删除操作后,日志中的记录为:

这里便是全部的日志,之前的进行put操作的记录完全不存在!
LevelDB的.log文件记录的是数据库中最近的一些操作,而不是全部操作。当LevelDB接收到写入或删除操作时,会将该操作写入.log文件中,但同时也会将该操作应用到内存中的memtable或磁盘中的sstable中。一旦memtable达到一定大小,或者sstable数量超过一定限制,LevelDB就会将其合并(Compaction),生成新的sstable,并在这个过程中将部分操作从.log文件中移除。
由于Compaction过程是有条件的,因此LevelDB的.log文件中不一定包含所有的操作记录。一些旧的操作记录可能会因为Compaction而被删除。另外,为了提高性能,LevelDB在日志文件中使用了一些技巧,比如批量写入(Batch Write)和写缓冲区(Write Buffer),这些技巧也可能导致某些操作记录没有被记录在.log文件中。
因此,如果您需要记录全部的操作记录,建议您在应用层面进行操作记录的记录,而不是依赖于LevelDB的.log文件。例如,您可以在应用中记录每个写入或删除操作的key-value对,以及其对应的时间戳或版本号。然后,您可以将这些记录保存到独立的日志文件中,或者写入到数据库中的特定key中。这样,您就可以完整地记录数据库的所有操作记录,包括那些因为Compaction而被删除的记录。同时,这种方式也可以更加灵活地控制操作记录的格式和内容,以满足不同的需求。
应用层面日志记录:
const logger = winston.createLogger({
level: 'info',
format: winston.format.json(),
defaultMeta: { service: 'leveldb' },
transports: [
new winston.transports.File({ filename: log + '/error.log', level: 'error' }),
new winston.transports.File({ filename: log + '/leveldb.log' }),
],
});
// 日志记录:
if (err) {
logger.error('Error writing value to LevelDB', { error: err });
reject(err);
} else {
logger.info('Value written to LevelDB', { key: key, value: value });
resolve("OK");
}