github.com/df-mc/goleveldb@v1.1.9/leveldb/db_snapshot.go (about) 1 // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com> 2 // All rights reserved. 3 // 4 // Use of this source code is governed by a BSD-style license that can be 5 // found in the LICENSE file. 6 7 package leveldb 8 9 import ( 10 "container/list" 11 "fmt" 12 "runtime" 13 "sync" 14 "sync/atomic" 15 16 "github.com/df-mc/goleveldb/leveldb/iterator" 17 "github.com/df-mc/goleveldb/leveldb/opt" 18 "github.com/df-mc/goleveldb/leveldb/util" 19 ) 20 21 type snapshotElement struct { 22 seq uint64 23 ref int 24 e *list.Element 25 } 26 27 // Acquires a snapshot, based on latest sequence. 28 func (db *DB) acquireSnapshot() *snapshotElement { 29 db.snapsMu.Lock() 30 defer db.snapsMu.Unlock() 31 32 seq := db.getSeq() 33 34 if e := db.snapsList.Back(); e != nil { 35 se := e.Value.(*snapshotElement) 36 if se.seq == seq { 37 se.ref++ 38 return se 39 } else if seq < se.seq { 40 panic("leveldb: sequence number is not increasing") 41 } 42 } 43 se := &snapshotElement{seq: seq, ref: 1} 44 se.e = db.snapsList.PushBack(se) 45 return se 46 } 47 48 // Releases given snapshot element. 49 func (db *DB) releaseSnapshot(se *snapshotElement) { 50 db.snapsMu.Lock() 51 defer db.snapsMu.Unlock() 52 53 se.ref-- 54 if se.ref == 0 { 55 db.snapsList.Remove(se.e) 56 se.e = nil 57 } else if se.ref < 0 { 58 panic("leveldb: Snapshot: negative element reference") 59 } 60 } 61 62 // Gets minimum sequence that not being snapshotted. 63 func (db *DB) minSeq() uint64 { 64 db.snapsMu.Lock() 65 defer db.snapsMu.Unlock() 66 67 if e := db.snapsList.Front(); e != nil { 68 return e.Value.(*snapshotElement).seq 69 } 70 71 return db.getSeq() 72 } 73 74 // Snapshot is a DB snapshot. 75 type Snapshot struct { 76 db *DB 77 elem *snapshotElement 78 mu sync.RWMutex 79 released bool 80 } 81 82 // Creates new snapshot object. 83 func (db *DB) newSnapshot() *Snapshot { 84 snap := &Snapshot{ 85 db: db, 86 elem: db.acquireSnapshot(), 87 } 88 atomic.AddInt32(&db.aliveSnaps, 1) 89 runtime.SetFinalizer(snap, (*Snapshot).Release) 90 return snap 91 } 92 93 func (snap *Snapshot) String() string { 94 return fmt.Sprintf("leveldb.Snapshot{%d}", snap.elem.seq) 95 } 96 97 // Get gets the value for the given key. It returns ErrNotFound if 98 // the DB does not contains the key. 99 // 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) { 103 err = snap.db.ok() 104 if err != nil { 105 return 106 } 107 snap.mu.RLock() 108 defer snap.mu.RUnlock() 109 if snap.released { 110 err = ErrSnapshotReleased 111 return 112 } 113 return snap.db.get(nil, nil, key, snap.elem.seq, ro) 114 } 115 116 // Has returns true if the DB does contains the given key. 117 // 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) { 120 err = snap.db.ok() 121 if err != nil { 122 return 123 } 124 snap.mu.RLock() 125 defer snap.mu.RUnlock() 126 if snap.released { 127 err = ErrSnapshotReleased 128 return 129 } 130 return snap.db.has(nil, nil, key, snap.elem.seq, ro) 131 } 132 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 138 // consistent. 139 // 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 143 // the DB. 144 // 145 // WARNING: Any slice returned by interator (e.g. slice returned by calling 146 // Iterator.Key() or Iterator.Value() methods), its content should not be 147 // modified unless noted otherwise. 148 // 149 // The iterator must be released after use, by calling Release method. 150 // Releasing the snapshot doesn't mean releasing the iterator too, the 151 // iterator would be still valid until released. 152 // 153 // Also read Iterator documentation of the leveldb/iterator package. 154 func (snap *Snapshot) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator { 155 if err := snap.db.ok(); err != nil { 156 return iterator.NewEmptyIterator(err) 157 } 158 snap.mu.Lock() 159 defer snap.mu.Unlock() 160 if snap.released { 161 return iterator.NewEmptyIterator(ErrSnapshotReleased) 162 } 163 // Since iterator already hold version ref, it doesn't need to 164 // hold snapshot ref. 165 return snap.db.newIterator(nil, nil, snap.elem.seq, slice, ro) 166 } 167 168 // Release releases the snapshot. This will not release any returned 169 // iterators, the iterators would still be valid until released or the 170 // underlying DB is closed. 171 // 172 // Other methods should not be called after the snapshot has been released. 173 func (snap *Snapshot) Release() { 174 snap.mu.Lock() 175 defer snap.mu.Unlock() 176 177 if !snap.released { 178 // Clear the finalizer. 179 runtime.SetFinalizer(snap, nil) 180 181 snap.released = true 182 snap.db.releaseSnapshot(snap.elem) 183 atomic.AddInt32(&snap.db.aliveSnaps, -1) 184 snap.db = nil 185 snap.elem = nil 186 } 187 }