level Snapshot源码分析

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/u012734441/article/details/81195140

​​# level Snapshot源码分析

上一篇文章中讲了WriteBatch,这一篇文章中开始讲快照Snapshot,Snapshot在文章中 leveldb中WriteBatch、Snapshot使用中讲过使用方法,这里面就不再继续讲用法了,这一节结合着之前写的Demo来讲源码。

Snapshot源码


之前写的demo为:

private final File databaseDir = FileUtils.createTempDir("leveldb");

    private final DBFactory factory = Iq80DBFactory.factory;

    File getTestDirectory(String name) throws IOException {
        File rc = new File(databaseDir, name);
        factory.destroy(rc, new Options().createIfMissing(true));
        rc.mkdirs();
        return rc;
    }

    @Test
    public void test01() throws IOException {
        Options options = new Options().createIfMissing(true).compressionType(CompressionType.NONE);
        File path = getTestDirectory("testSnapshot");
        DB db = factory.open(path, options);
        WriteOptions writeOptions = new WriteOptions();
        db.put(Iq80DBFactory.bytes("key"), Iq80DBFactory.bytes("value" + 1), writeOptions);
        ReadOptions readOptions = new ReadOptions();
        Snapshot snapshot = db.getSnapshot();
        readOptions.snapshot(snapshot);
        String value2 = "value2";
        db.put(Iq80DBFactory.bytes("key"), Iq80DBFactory.bytes(value2), new WriteOptions());
        byte[] value = db.get(Iq80DBFactory.bytes("key"), new ReadOptions());
        System.out.println(Iq80DBFactory.asString(value));

        byte[] value3 = db.get(Iq80DBFactory.bytes("key"), readOptions);
        System.out.println(Iq80DBFactory.asString(value3));

        snapshot.close();
        db.close();
    }

leveldb的快照主要功能是用来读取某个时间点之前的数据,因为leveldb在插入数据时,键值是可以一样的,所以当查询这个键值时,系统返回的是最新的数据,也就是后面插入的数据。但是如果在第二次插入相同键值数据之前,建立一个快照,那么读取这个快照时,读取的就是这个快照时间点之前的数据。

上述代码不再演示,我们直接来看看Snapshot源码,其实Snapshot中最关键的还是有一个lastSequence字段,部分源码如下:

private final AtomicBoolean closed = new AtomicBoolean();
    private final Version version;
    private final long lastSequence;

在leveldb快照中每次都是用一个序列号保存当前插入的这一条记录,因此当插入多条相同的记录时,通过序列号来确定那一条是最新的记录,在leveldb的快照中,在调用一个快照时,只要获取在当前快照序列号以下的记录,就可以读取到这个快照之前的数据,这也就是leveldb中快照的原理。

我们可以看下这一行代码:

db.get(Iq80DBFactory.bytes("key"), readOptions);

readOptions中保存了当前的快照,我们去看下get源码,如下:

SnapshotImpl snapshot = getSnapshot(options);
            lookupKey = new LookupKey(Slices.wrappedBuffer(key), snapshot.getLastSequence());

            // First look in the memtable, then in the immutable memtable (if any).
            LookupResult lookupResult = memTable.get(lookupKey);

在拿到快照后,取出快照中的sequence number,根据传入的key和sequence number进文件中查找记录,这样就能查找快照之前的数据。

获取快照的方法为:

private SnapshotImpl getSnapshot(ReadOptions options)
    {
        SnapshotImpl snapshot;
        if (options.snapshot() != null) {
            snapshot = (SnapshotImpl) options.snapshot();
        }
        else {
            snapshot = new SnapshotImpl(versions.getCurrent(), versions.getLastSequence());
            snapshot.close(); // To avoid holding the snapshot active..
        }
        return snapshot;
    }

就是取出之前保存在readOption中的Snapshot,没有太多特殊的地方。

在保存当前快照时,取出当前version与序列号生成快照并返回,如下:

public Snapshot getSnapshot()
    {
        checkBackgroundException();
        mutex.lock();
        try {
            return new SnapshotImpl(versions.getCurrent(), versions.getLastSequence());
        }
        finally {
            mutex.unlock();
        }
    }

快照在这里并不是简简单单的序列号,而是还有一个version对象,这个对象中保存了当前节点的文件元数据信息,level层级等等,这些都是在寻找快照之前数据时使用的。


下一节讲Snapshot中提到的Version、VersionSet。

猜你喜欢

转载自blog.csdn.net/u012734441/article/details/81195140