OSDN Git Service

new repo
[bytom/vapor.git] / vendor / github.com / syndtr / goleveldb / leveldb / db_snapshot.go
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/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 // 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 // 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 }