github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/syndtr/goleveldb/leveldb/db_snapshot.go (about)

     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/insionng/yougam/libraries/syndtr/goleveldb/leveldb/iterator"
    17  	"github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/opt"
    18  	"github.com/insionng/yougam/libraries/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 snapshoted.
    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 goroutine-safe, 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  }