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

     1  // Copyright (c) 2013, 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  	"sync/atomic"
    11  	"time"
    12  
    13  	"github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/journal"
    14  	"github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/memdb"
    15  	"github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/storage"
    16  )
    17  
    18  type memDB struct {
    19  	db *DB
    20  	*memdb.DB
    21  	ref int32
    22  }
    23  
    24  func (m *memDB) getref() int32 {
    25  	return atomic.LoadInt32(&m.ref)
    26  }
    27  
    28  func (m *memDB) incref() {
    29  	atomic.AddInt32(&m.ref, 1)
    30  }
    31  
    32  func (m *memDB) decref() {
    33  	if ref := atomic.AddInt32(&m.ref, -1); ref == 0 {
    34  		// Only put back memdb with std capacity.
    35  		if m.Capacity() == m.db.s.o.GetWriteBuffer() {
    36  			m.Reset()
    37  			m.db.mpoolPut(m.DB)
    38  		}
    39  		m.db = nil
    40  		m.DB = nil
    41  	} else if ref < 0 {
    42  		panic("negative memdb ref")
    43  	}
    44  }
    45  
    46  // Get latest sequence number.
    47  func (db *DB) getSeq() uint64 {
    48  	return atomic.LoadUint64(&db.seq)
    49  }
    50  
    51  // Atomically adds delta to seq.
    52  func (db *DB) addSeq(delta uint64) {
    53  	atomic.AddUint64(&db.seq, delta)
    54  }
    55  
    56  func (db *DB) setSeq(seq uint64) {
    57  	atomic.StoreUint64(&db.seq, seq)
    58  }
    59  
    60  func (db *DB) sampleSeek(ikey internalKey) {
    61  	v := db.s.version()
    62  	if v.sampleSeek(ikey) {
    63  		// Trigger table compaction.
    64  		db.compTrigger(db.tcompCmdC)
    65  	}
    66  	v.release()
    67  }
    68  
    69  func (db *DB) mpoolPut(mem *memdb.DB) {
    70  	defer func() {
    71  		recover()
    72  	}()
    73  	select {
    74  	case db.memPool <- mem:
    75  	default:
    76  	}
    77  }
    78  
    79  func (db *DB) mpoolGet(n int) *memDB {
    80  	var mdb *memdb.DB
    81  	select {
    82  	case mdb = <-db.memPool:
    83  	default:
    84  	}
    85  	if mdb == nil || mdb.Capacity() < n {
    86  		mdb = memdb.New(db.s.icmp, maxInt(db.s.o.GetWriteBuffer(), n))
    87  	}
    88  	return &memDB{
    89  		db: db,
    90  		DB: mdb,
    91  	}
    92  }
    93  
    94  func (db *DB) mpoolDrain() {
    95  	ticker := time.NewTicker(30 * time.Second)
    96  	for {
    97  		select {
    98  		case <-ticker.C:
    99  			select {
   100  			case <-db.memPool:
   101  			default:
   102  			}
   103  		case _, _ = <-db.closeC:
   104  			close(db.memPool)
   105  			return
   106  		}
   107  	}
   108  }
   109  
   110  // Create new memdb and froze the old one; need external synchronization.
   111  // newMem only called synchronously by the writer.
   112  func (db *DB) newMem(n int) (mem *memDB, err error) {
   113  	fd := storage.FileDesc{Type: storage.TypeJournal, Num: db.s.allocFileNum()}
   114  	w, err := db.s.stor.Create(fd)
   115  	if err != nil {
   116  		db.s.reuseFileNum(fd.Num)
   117  		return
   118  	}
   119  
   120  	db.memMu.Lock()
   121  	defer db.memMu.Unlock()
   122  
   123  	if db.frozenMem != nil {
   124  		panic("still has frozen mem")
   125  	}
   126  
   127  	if db.journal == nil {
   128  		db.journal = journal.NewWriter(w)
   129  	} else {
   130  		db.journal.Reset(w)
   131  		db.journalWriter.Close()
   132  		db.frozenJournalFd = db.journalFd
   133  	}
   134  	db.journalWriter = w
   135  	db.journalFd = fd
   136  	db.frozenMem = db.mem
   137  	mem = db.mpoolGet(n)
   138  	mem.incref() // for self
   139  	mem.incref() // for caller
   140  	db.mem = mem
   141  	// The seq only incremented by the writer. And whoever called newMem
   142  	// should hold write lock, so no need additional synchronization here.
   143  	db.frozenSeq = db.seq
   144  	return
   145  }
   146  
   147  // Get all memdbs.
   148  func (db *DB) getMems() (e, f *memDB) {
   149  	db.memMu.RLock()
   150  	defer db.memMu.RUnlock()
   151  	if db.mem == nil {
   152  		panic("nil effective mem")
   153  	}
   154  	db.mem.incref()
   155  	if db.frozenMem != nil {
   156  		db.frozenMem.incref()
   157  	}
   158  	return db.mem, db.frozenMem
   159  }
   160  
   161  // Get frozen memdb.
   162  func (db *DB) getEffectiveMem() *memDB {
   163  	db.memMu.RLock()
   164  	defer db.memMu.RUnlock()
   165  	if db.mem == nil {
   166  		panic("nil effective mem")
   167  	}
   168  	db.mem.incref()
   169  	return db.mem
   170  }
   171  
   172  // Check whether we has frozen memdb.
   173  func (db *DB) hasFrozenMem() bool {
   174  	db.memMu.RLock()
   175  	defer db.memMu.RUnlock()
   176  	return db.frozenMem != nil
   177  }
   178  
   179  // Get frozen memdb.
   180  func (db *DB) getFrozenMem() *memDB {
   181  	db.memMu.RLock()
   182  	defer db.memMu.RUnlock()
   183  	if db.frozenMem != nil {
   184  		db.frozenMem.incref()
   185  	}
   186  	return db.frozenMem
   187  }
   188  
   189  // Drop frozen memdb; assume that frozen memdb isn't nil.
   190  func (db *DB) dropFrozenMem() {
   191  	db.memMu.Lock()
   192  	if err := db.s.stor.Remove(db.frozenJournalFd); err != nil {
   193  		db.logf("journal@remove removing @%d %q", db.frozenJournalFd.Num, err)
   194  	} else {
   195  		db.logf("journal@remove removed @%d", db.frozenJournalFd.Num)
   196  	}
   197  	db.frozenJournalFd = storage.FileDesc{}
   198  	db.frozenMem.decref()
   199  	db.frozenMem = nil
   200  	db.memMu.Unlock()
   201  }
   202  
   203  // Set closed flag; return true if not already closed.
   204  func (db *DB) setClosed() bool {
   205  	return atomic.CompareAndSwapUint32(&db.closed, 0, 1)
   206  }
   207  
   208  // Check whether DB was closed.
   209  func (db *DB) isClosed() bool {
   210  	return atomic.LoadUint32(&db.closed) != 0
   211  }
   212  
   213  // Check read ok status.
   214  func (db *DB) ok() error {
   215  	if db.isClosed() {
   216  		return ErrClosed
   217  	}
   218  	return nil
   219  }