123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187 |
- // Copyright (c) 2012, Suryandaru Triandana <syndtr@gmail.com>
- // All rights reserved.
- //
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- package leveldb
- import (
- "container/list"
- "fmt"
- "runtime"
- "sync"
- "sync/atomic"
- "github.com/syndtr/goleveldb/leveldb/iterator"
- "github.com/syndtr/goleveldb/leveldb/opt"
- "github.com/syndtr/goleveldb/leveldb/util"
- )
- type snapshotElement struct {
- seq uint64
- ref int
- e *list.Element
- }
- // Acquires a snapshot, based on latest sequence.
- func (db *DB) acquireSnapshot() *snapshotElement {
- db.snapsMu.Lock()
- defer db.snapsMu.Unlock()
- seq := db.getSeq()
- if e := db.snapsList.Back(); e != nil {
- se := e.Value.(*snapshotElement)
- if se.seq == seq {
- se.ref++
- return se
- } else if seq < se.seq {
- panic("leveldb: sequence number is not increasing")
- }
- }
- se := &snapshotElement{seq: seq, ref: 1}
- se.e = db.snapsList.PushBack(se)
- return se
- }
- // Releases given snapshot element.
- func (db *DB) releaseSnapshot(se *snapshotElement) {
- db.snapsMu.Lock()
- defer db.snapsMu.Unlock()
- se.ref--
- if se.ref == 0 {
- db.snapsList.Remove(se.e)
- se.e = nil
- } else if se.ref < 0 {
- panic("leveldb: Snapshot: negative element reference")
- }
- }
- // Gets minimum sequence that not being snapshotted.
- func (db *DB) minSeq() uint64 {
- db.snapsMu.Lock()
- defer db.snapsMu.Unlock()
- if e := db.snapsList.Front(); e != nil {
- return e.Value.(*snapshotElement).seq
- }
- return db.getSeq()
- }
- // Snapshot is a DB snapshot.
- type Snapshot struct {
- db *DB
- elem *snapshotElement
- mu sync.RWMutex
- released bool
- }
- // Creates new snapshot object.
- func (db *DB) newSnapshot() *Snapshot {
- snap := &Snapshot{
- db: db,
- elem: db.acquireSnapshot(),
- }
- atomic.AddInt32(&db.aliveSnaps, 1)
- runtime.SetFinalizer(snap, (*Snapshot).Release)
- return snap
- }
- func (snap *Snapshot) String() string {
- return fmt.Sprintf("leveldb.Snapshot{%d}", snap.elem.seq)
- }
- // Get gets the value for the given key. It returns ErrNotFound if
- // the DB does not contains the key.
- //
- // The caller should not modify the contents of the returned slice, but
- // it is safe to modify the contents of the argument after Get returns.
- func (snap *Snapshot) Get(key []byte, ro *opt.ReadOptions) (value []byte, err error) {
- err = snap.db.ok()
- if err != nil {
- return
- }
- snap.mu.RLock()
- defer snap.mu.RUnlock()
- if snap.released {
- err = ErrSnapshotReleased
- return
- }
- return snap.db.get(nil, nil, key, snap.elem.seq, ro)
- }
- // Has returns true if the DB does contains the given key.
- //
- // It is safe to modify the contents of the argument after Get returns.
- func (snap *Snapshot) Has(key []byte, ro *opt.ReadOptions) (ret bool, err error) {
- err = snap.db.ok()
- if err != nil {
- return
- }
- snap.mu.RLock()
- defer snap.mu.RUnlock()
- if snap.released {
- err = ErrSnapshotReleased
- return
- }
- return snap.db.has(nil, nil, key, snap.elem.seq, ro)
- }
- // NewIterator returns an iterator for the snapshot of the underlying DB.
- // The returned iterator is not safe for concurrent use, but it is safe to use
- // multiple iterators concurrently, with each in a dedicated goroutine.
- // It is also safe to use an iterator concurrently with modifying its
- // underlying DB. The resultant key/value pairs are guaranteed to be
- // consistent.
- //
- // Slice allows slicing the iterator to only contains keys in the given
- // range. A nil Range.Start is treated as a key before all keys in the
- // DB. And a nil Range.Limit is treated as a key after all keys in
- // the DB.
- //
- // WARNING: Any slice returned by interator (e.g. slice returned by calling
- // Iterator.Key() or Iterator.Value() methods), its content should not be
- // modified unless noted otherwise.
- //
- // The iterator must be released after use, by calling Release method.
- // Releasing the snapshot doesn't mean releasing the iterator too, the
- // iterator would be still valid until released.
- //
- // Also read Iterator documentation of the leveldb/iterator package.
- func (snap *Snapshot) NewIterator(slice *util.Range, ro *opt.ReadOptions) iterator.Iterator {
- if err := snap.db.ok(); err != nil {
- return iterator.NewEmptyIterator(err)
- }
- snap.mu.Lock()
- defer snap.mu.Unlock()
- if snap.released {
- return iterator.NewEmptyIterator(ErrSnapshotReleased)
- }
- // Since iterator already hold version ref, it doesn't need to
- // hold snapshot ref.
- return snap.db.newIterator(nil, nil, snap.elem.seq, slice, ro)
- }
- // Release releases the snapshot. This will not release any returned
- // iterators, the iterators would still be valid until released or the
- // underlying DB is closed.
- //
- // Other methods should not be called after the snapshot has been released.
- func (snap *Snapshot) Release() {
- snap.mu.Lock()
- defer snap.mu.Unlock()
- if !snap.released {
- // Clear the finalizer.
- runtime.SetFinalizer(snap, nil)
- snap.released = true
- snap.db.releaseSnapshot(snap.elem)
- atomic.AddInt32(&snap.db.aliveSnaps, -1)
- snap.db = nil
- snap.elem = nil
- }
- }
|