...
1
2
3
4
5
6
7 package leveldb
8
9 import (
10 "container/list"
11 "fmt"
12 "runtime"
13 "sync"
14 "sync/atomic"
15
16 "github.com/syndtr/goleveldb/leveldb/iterator"
17 "github.com/syndtr/goleveldb/leveldb/opt"
18 "github.com/syndtr/goleveldb/leveldb/util"
19 )
20
21 type snapshotElement struct {
22 seq uint64
23 ref int
24 e *list.Element
25 }
26
27
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
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
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
75 type Snapshot struct {
76 db *DB
77 elem *snapshotElement
78 mu sync.RWMutex
79 released bool
80 }
81
82
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
98
99
100
101
102 func (snap *Snapshot) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) {
103 snap.mu.RLock()
104 defer snap.mu.RUnlock()
105 if snap.released {
106 err = ErrSnapshotReleased
107 return
108 }
109 err = snap.db.ok()
110 if err != nil {
111 return
112 }
113 return snap.db.get(nil, nil, key, snap.elem.seq, ro)
114 }
115
116
117
118
119 func (snap *Snapshot) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error) {
120 snap.mu.RLock()
121 defer snap.mu.RUnlock()
122 if snap.released {
123 err = ErrSnapshotReleased
124 return
125 }
126 err = snap.db.ok()
127 if err != nil {
128 return
129 }
130 return snap.db.has(nil, nil, key, snap.elem.seq, ro)
131 }
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154 func (snap *Snapshot) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator {
155 snap.mu.Lock()
156 defer snap.mu.Unlock()
157 if snap.released {
158 return iterator.NewEmptyIterator(ErrSnapshotReleased)
159 }
160 if err := snap.db.ok(); err != nil {
161 return iterator.NewEmptyIterator(err)
162 }
163
164
165 return snap.db.newIterator(nil, nil, snap.elem.seq, slice, ro)
166 }
167
168
169
170
171
172
173 func (snap *Snapshot) Release() {
174 snap.mu.Lock()
175 defer snap.mu.Unlock()
176
177 if !snap.released {
178
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 }
188
View as plain text