You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

183 lines
4.7 KiB

  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. // The iterator must be released after use, by calling Release method.
  128. // Releasing the snapshot doesn't mean releasing the iterator too, the
  129. // iterator would be still valid until released.
  130. //
  131. // Also read Iterator documentation of the leveldb/iterator package.
  132. func (snap *Snapshot) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator {
  133. if err := snap.db.ok(); err != nil {
  134. return iterator.NewEmptyIterator(err)
  135. }
  136. snap.mu.Lock()
  137. defer snap.mu.Unlock()
  138. if snap.released {
  139. return iterator.NewEmptyIterator(ErrSnapshotReleased)
  140. }
  141. // Since iterator already hold version ref, it doesn't need to
  142. // hold snapshot ref.
  143. return snap.db.newIterator(nil, nil, snap.elem.seq, slice, ro)
  144. }
  145. // Release releases the snapshot. This will not release any returned
  146. // iterators, the iterators would still be valid until released or the
  147. // underlying DB is closed.
  148. //
  149. // Other methods should not be called after the snapshot has been released.
  150. func (snap *Snapshot) Release() {
  151. snap.mu.Lock()
  152. defer snap.mu.Unlock()
  153. if !snap.released {
  154. // Clear the finalizer.
  155. runtime.SetFinalizer(snap, nil)
  156. snap.released = true
  157. snap.db.releaseSnapshot(snap.elem)
  158. atomic.AddInt32(&snap.db.aliveSnaps, -1)
  159. snap.db = nil
  160. snap.elem = nil
  161. }
  162. }