github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/syndtr/goleveldb/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/insionng/yougam/libraries/syndtr/goleveldb/leveldb/iterator" 17 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/opt" 18 "github.com/insionng/yougam/libraries/syndtr/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 snapshoted. 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 goroutine-safe, 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 // 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. 148 // 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) 153 } 154 snap.mu.Lock() 155 defer snap.mu.Unlock() 156 if snap.released { 157 return iterator.NewEmptyIterator(ErrSnapshotReleased) 158 } 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) 162 } 163 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. 167 // 168 // Other methods should not be called after the snapshot has been released. 169 func (snap *Snapshot) Release() { 170 snap.mu.Lock() 171 defer snap.mu.Unlock() 172 173 if !snap.released { 174 // Clear the finalizer. 175 runtime.SetFinalizer(snap, nil) 176 177 snap.released = true 178 snap.db.releaseSnapshot(snap.elem) 179 atomic.AddInt32(&snap.db.aliveSnaps, -1) 180 snap.db = nil 181 snap.elem = nil 182 } 183 }