1 // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
2 // All rights reserved.
4 // Use of this source code is governed by a BSD-style license that can be
5 // found in the LICENSE file.
16 "github.com/syndtr/goleveldb/leveldb/iterator"
17 "github.com/syndtr/goleveldb/leveldb/opt"
18 "github.com/syndtr/goleveldb/leveldb/util"
21 type snapshotElement struct {
27 // Acquires a snapshot, based on latest sequence.
28 func (db *DB) acquireSnapshot() *snapshotElement {
30 defer db.snapsMu.Unlock()
34 if e := db.snapsList.Back(); e != nil {
35 se := e.Value.(*snapshotElement)
39 } else if seq < se.seq {
40 panic("leveldb: sequence number is not increasing")
43 se := &snapshotElement{seq: seq, ref: 1}
44 se.e = db.snapsList.PushBack(se)
48 // Releases given snapshot element.
49 func (db *DB) releaseSnapshot(se *snapshotElement) {
51 defer db.snapsMu.Unlock()
55 db.snapsList.Remove(se.e)
57 } else if se.ref < 0 {
58 panic("leveldb: Snapshot: negative element reference")
62 // Gets minimum sequence that not being snapshotted.
63 func (db *DB) minSeq() uint64 {
65 defer db.snapsMu.Unlock()
67 if e := db.snapsList.Front(); e != nil {
68 return e.Value.(*snapshotElement).seq
74 // Snapshot is a DB snapshot.
75 type Snapshot struct {
82 // Creates new snapshot object.
83 func (db *DB) newSnapshot() *Snapshot {
86 elem: db.acquireSnapshot(),
88 atomic.AddInt32(&db.aliveSnaps, 1)
89 runtime.SetFinalizer(snap, (*Snapshot).Release)
93 func (snap *Snapshot) String() string {
94 return fmt.Sprintf("leveldb.Snapshot{%d}", snap.elem.seq)
97 // Get gets the value for the given key. It returns ErrNotFound if
98 // the DB does not contains the key.
100 // The caller should not modify the contents of the returned slice, but
101 // it is safe to modify the contents of the argument after Get returns.
102 func (snap *Snapshot) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) {
108 defer snap.mu.RUnlock()
110 err = ErrSnapshotReleased
113 return snap.db.get(nil, nil, key, snap.elem.seq, ro)
116 // Has returns true if the DB does contains the given key.
118 // It is safe to modify the contents of the argument after Get returns.
119 func (snap *Snapshot) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error) {
125 defer snap.mu.RUnlock()
127 err = ErrSnapshotReleased
130 return snap.db.has(nil, nil, key, snap.elem.seq, ro)
133 // NewIterator returns an iterator for the snapshot of the underlying DB.
134 // The returned iterator is not safe for concurrent use, but it is safe to use
135 // multiple iterators concurrently, with each in a dedicated goroutine.
136 // It is also safe to use an iterator concurrently with modifying its
137 // underlying DB. The resultant key/value pairs are guaranteed to be
140 // Slice allows slicing the iterator to only contains keys in the given
141 // range. A nil Range.Start is treated as a key before all keys in the
142 // DB. And a nil Range.Limit is treated as a key after all keys in
145 // The iterator must be released after use, by calling Release method.
146 // Releasing the snapshot doesn't mean releasing the iterator too, the
147 // iterator would be still valid until released.
149 // Also read Iterator documentation of the leveldb/iterator package.
150 func (snap *Snapshot) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator {
151 if err := snap.db.ok(); err != nil {
152 return iterator.NewEmptyIterator(err)
155 defer snap.mu.Unlock()
157 return iterator.NewEmptyIterator(ErrSnapshotReleased)
159 // Since iterator already hold version ref, it doesn't need to
160 // hold snapshot ref.
161 return snap.db.newIterator(nil, nil, snap.elem.seq, slice, ro)
164 // Release releases the snapshot. This will not release any returned
165 // iterators, the iterators would still be valid until released or the
166 // underlying DB is closed.
168 // Other methods should not be called after the snapshot has been released.
169 func (snap *Snapshot) Release() {
171 defer snap.mu.Unlock()
174 // Clear the finalizer.
175 runtime.SetFinalizer(snap, nil)
178 snap.db.releaseSnapshot(snap.elem)
179 atomic.AddInt32(&snap.db.aliveSnaps, -1)