db_snapshot.go 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187
  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. package leveldb
  7. import (
  8. "container/list"
  9. "fmt"
  10. "runtime"
  11. "sync"
  12. "sync/atomic"
  13. "github.com/syndtr/goleveldb/leveldb/iterator"
  14. "github.com/syndtr/goleveldb/leveldb/opt"
  15. "github.com/syndtr/goleveldb/leveldb/util"
  16. )
  17. type snapshotElement struct {
  18. seq uint64
  19. ref int
  20. e *list.Element
  21. }
  22. // Acquires a snapshot, based on latest sequence.
  23. func (db *DB) acquireSnapshot() *snapshotElement {
  24. db.snapsMu.Lock()
  25. defer db.snapsMu.Unlock()
  26. seq := db.getSeq()
  27. if e := db.snapsList.Back(); e != nil {
  28. se := e.Value.(*snapshotElement)
  29. if se.seq == seq {
  30. se.ref++
  31. return se
  32. } else if seq < se.seq {
  33. panic("leveldb: sequence number is not increasing")
  34. }
  35. }
  36. se := &snapshotElement{seq: seq, ref: 1}
  37. se.e = db.snapsList.PushBack(se)
  38. return se
  39. }
  40. // Releases given snapshot element.
  41. func (db *DB) releaseSnapshot(se *snapshotElement) {
  42. db.snapsMu.Lock()
  43. defer db.snapsMu.Unlock()
  44. se.ref--
  45. if se.ref == 0 {
  46. db.snapsList.Remove(se.e)
  47. se.e = nil
  48. } else if se.ref < 0 {
  49. panic("leveldb: Snapshot: negative element reference")
  50. }
  51. }
  52. // Gets minimum sequence that not being snapshotted.
  53. func (db *DB) minSeq() uint64 {
  54. db.snapsMu.Lock()
  55. defer db.snapsMu.Unlock()
  56. if e := db.snapsList.Front(); e != nil {
  57. return e.Value.(*snapshotElement).seq
  58. }
  59. return db.getSeq()
  60. }
  61. // Snapshot is a DB snapshot.
  62. type Snapshot struct {
  63. db *DB
  64. elem *snapshotElement
  65. mu sync.RWMutex
  66. released bool
  67. }
  68. // Creates new snapshot object.
  69. func (db *DB) newSnapshot() *Snapshot {
  70. snap := &Snapshot{
  71. db: db,
  72. elem: db.acquireSnapshot(),
  73. }
  74. atomic.AddInt32(&db.aliveSnaps, 1)
  75. runtime.SetFinalizer(snap, (*Snapshot).Release)
  76. return snap
  77. }
  78. func (snap *Snapshot) String() string {
  79. return fmt.Sprintf("leveldb.Snapshot{%d}", snap.elem.seq)
  80. }
  81. // Get gets the value for the given key. It returns ErrNotFound if
  82. // the DB does not contains the key.
  83. //
  84. // The caller should not modify the contents of the returned slice, but
  85. // it is safe to modify the contents of the argument after Get returns.
  86. func (snap *Snapshot) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) {
  87. err = snap.db.ok()
  88. if err != nil {
  89. return
  90. }
  91. snap.mu.RLock()
  92. defer snap.mu.RUnlock()
  93. if snap.released {
  94. err = ErrSnapshotReleased
  95. return
  96. }
  97. return snap.db.get(nil, nil, key, snap.elem.seq, ro)
  98. }
  99. // Has returns true if the DB does contains the given key.
  100. //
  101. // It is safe to modify the contents of the argument after Get returns.
  102. func (snap *Snapshot) Has(key []byte, ro *opt.ReadOptions) (ret bool, 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.has(nil, nil, key, snap.elem.seq, ro)
  114. }
  115. // NewIterator returns an iterator for the snapshot of the underlying DB.
  116. // The returned iterator is not safe for concurrent use, but it is safe to use
  117. // multiple iterators concurrently, with each in a dedicated goroutine.
  118. // It is also safe to use an iterator concurrently with modifying its
  119. // underlying DB. The resultant key/value pairs are guaranteed to be
  120. // consistent.
  121. //
  122. // Slice allows slicing the iterator to only contains keys in the given
  123. // range. A nil Range.Start is treated as a key before all keys in the
  124. // DB. And a nil Range.Limit is treated as a key after all keys in
  125. // the DB.
  126. //
  127. // WARNING: Any slice returned by interator (e.g. slice returned by calling
  128. // Iterator.Key() or Iterator.Value() methods), its content should not be
  129. // modified unless noted otherwise.
  130. //
  131. // The iterator must be released after use, by calling Release method.
  132. // Releasing the snapshot doesn't mean releasing the iterator too, the
  133. // iterator would be still valid until released.
  134. //
  135. // Also read Iterator documentation of the leveldb/iterator package.
  136. func (snap *Snapshot) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator {
  137. if err := snap.db.ok(); err != nil {
  138. return iterator.NewEmptyIterator(err)
  139. }
  140. snap.mu.Lock()
  141. defer snap.mu.Unlock()
  142. if snap.released {
  143. return iterator.NewEmptyIterator(ErrSnapshotReleased)
  144. }
  145. // Since iterator already hold version ref, it doesn't need to
  146. // hold snapshot ref.
  147. return snap.db.newIterator(nil, nil, snap.elem.seq, slice, ro)
  148. }
  149. // Release releases the snapshot. This will not release any returned
  150. // iterators, the iterators would still be valid until released or the
  151. // underlying DB is closed.
  152. //
  153. // Other methods should not be called after the snapshot has been released.
  154. func (snap *Snapshot) Release() {
  155. snap.mu.Lock()
  156. defer snap.mu.Unlock()
  157. if !snap.released {
  158. // Clear the finalizer.
  159. runtime.SetFinalizer(snap, nil)
  160. snap.released = true
  161. snap.db.releaseSnapshot(snap.elem)
  162. atomic.AddInt32(&snap.db.aliveSnaps, -1)
  163. snap.db = nil
  164. snap.elem = nil
  165. }
  166. }