syncthing/vendor/github.com/syndtr/goleveldb/leveldb/db_state.go

220 lines
4.3 KiB
Go
Raw Normal View History

2014-07-06 12:46:48 +00:00
// Copyright (c) 2013, 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 (
"sync/atomic"
2014-09-02 07:43:42 +00:00
"time"
2014-07-06 12:46:48 +00:00
"github.com/syndtr/goleveldb/leveldb/journal"
"github.com/syndtr/goleveldb/leveldb/memdb"
"github.com/syndtr/goleveldb/leveldb/storage"
2014-07-06 12:46:48 +00:00
)
2014-08-15 07:16:30 +00:00
type memDB struct {
2015-06-15 19:10:18 +00:00
db *DB
*memdb.DB
2014-09-02 07:43:42 +00:00
ref int32
2014-08-15 07:16:30 +00:00
}
func (m *memDB) getref() int32 {
return atomic.LoadInt32(&m.ref)
}
2014-08-15 07:16:30 +00:00
func (m *memDB) incref() {
atomic.AddInt32(&m.ref, 1)
}
func (m *memDB) decref() {
if ref := atomic.AddInt32(&m.ref, -1); ref == 0 {
2014-09-02 07:43:42 +00:00
// Only put back memdb with std capacity.
2015-06-15 19:10:18 +00:00
if m.Capacity() == m.db.s.o.GetWriteBuffer() {
m.Reset()
m.db.mpoolPut(m.DB)
2014-09-02 07:43:42 +00:00
}
m.db = nil
2015-06-15 19:10:18 +00:00
m.DB = nil
2014-08-15 07:16:30 +00:00
} else if ref < 0 {
panic("negative memdb ref")
}
}
2014-07-06 12:46:48 +00:00
// Get latest sequence number.
2014-07-23 06:31:36 +00:00
func (db *DB) getSeq() uint64 {
return atomic.LoadUint64(&db.seq)
2014-07-06 12:46:48 +00:00
}
// Atomically adds delta to seq.
2014-07-23 06:31:36 +00:00
func (db *DB) addSeq(delta uint64) {
atomic.AddUint64(&db.seq, delta)
2014-07-06 12:46:48 +00:00
}
func (db *DB) setSeq(seq uint64) {
atomic.StoreUint64(&db.seq, seq)
}
func (db *DB) sampleSeek(ikey internalKey) {
2015-06-15 19:10:18 +00:00
v := db.s.version()
if v.sampleSeek(ikey) {
// Trigger table compaction.
db.compTrigger(db.tcompCmdC)
2015-06-15 19:10:18 +00:00
}
v.release()
}
2014-09-02 07:43:42 +00:00
func (db *DB) mpoolPut(mem *memdb.DB) {
defer func() {
recover()
}()
select {
case db.memPool <- mem:
default:
}
}
func (db *DB) mpoolGet(n int) *memDB {
var mdb *memdb.DB
2014-09-02 07:43:42 +00:00
select {
case mdb = <-db.memPool:
2014-09-02 07:43:42 +00:00
default:
}
if mdb == nil || mdb.Capacity() < n {
mdb = memdb.New(db.s.icmp, maxInt(db.s.o.GetWriteBuffer(), n))
}
return &memDB{
db: db,
DB: mdb,
2014-09-02 07:43:42 +00:00
}
}
func (db *DB) mpoolDrain() {
ticker := time.NewTicker(30 * time.Second)
for {
select {
case <-ticker.C:
select {
case <-db.memPool:
default:
}
case _, _ = <-db.closeC:
close(db.memPool)
return
}
}
}
2014-07-06 12:46:48 +00:00
// Create new memdb and froze the old one; need external synchronization.
// newMem only called synchronously by the writer.
2014-08-15 07:16:30 +00:00
func (db *DB) newMem(n int) (mem *memDB, err error) {
fd := storage.FileDesc{Type: storage.TypeJournal, Num: db.s.allocFileNum()}
w, err := db.s.stor.Create(fd)
2014-07-06 12:46:48 +00:00
if err != nil {
db.s.reuseFileNum(fd.Num)
2014-07-06 12:46:48 +00:00
return
}
2014-07-23 06:31:36 +00:00
db.memMu.Lock()
defer db.memMu.Unlock()
2014-08-15 07:16:30 +00:00
if db.frozenMem != nil {
panic("still has frozen mem")
}
2014-07-23 06:31:36 +00:00
if db.journal == nil {
db.journal = journal.NewWriter(w)
2014-07-06 12:46:48 +00:00
} else {
2014-07-23 06:31:36 +00:00
db.journal.Reset(w)
db.journalWriter.Close()
db.frozenJournalFd = db.journalFd
2014-07-06 12:46:48 +00:00
}
2014-07-23 06:31:36 +00:00
db.journalWriter = w
db.journalFd = fd
2014-07-23 06:31:36 +00:00
db.frozenMem = db.mem
mem = db.mpoolGet(n)
mem.incref() // for self
mem.incref() // for caller
2014-08-15 07:16:30 +00:00
db.mem = mem
2014-07-23 06:31:36 +00:00
// The seq only incremented by the writer. And whoever called newMem
// should hold write lock, so no need additional synchronization here.
db.frozenSeq = db.seq
2014-07-06 12:46:48 +00:00
return
}
// Get all memdbs.
2014-08-15 07:16:30 +00:00
func (db *DB) getMems() (e, f *memDB) {
2014-07-23 06:31:36 +00:00
db.memMu.RLock()
defer db.memMu.RUnlock()
2014-08-15 07:16:30 +00:00
if db.mem == nil {
panic("nil effective mem")
}
db.mem.incref()
if db.frozenMem != nil {
db.frozenMem.incref()
}
2014-07-23 06:31:36 +00:00
return db.mem, db.frozenMem
2014-07-06 12:46:48 +00:00
}
// Get frozen memdb.
2014-08-15 07:16:30 +00:00
func (db *DB) getEffectiveMem() *memDB {
2014-07-23 06:31:36 +00:00
db.memMu.RLock()
defer db.memMu.RUnlock()
2014-08-15 07:16:30 +00:00
if db.mem == nil {
panic("nil effective mem")
}
db.mem.incref()
2014-07-23 06:31:36 +00:00
return db.mem
2014-07-06 12:46:48 +00:00
}
// Check whether we has frozen memdb.
2014-07-23 06:31:36 +00:00
func (db *DB) hasFrozenMem() bool {
db.memMu.RLock()
defer db.memMu.RUnlock()
return db.frozenMem != nil
2014-07-06 12:46:48 +00:00
}
// Get frozen memdb.
2014-08-15 07:16:30 +00:00
func (db *DB) getFrozenMem() *memDB {
2014-07-23 06:31:36 +00:00
db.memMu.RLock()
defer db.memMu.RUnlock()
2014-08-15 07:16:30 +00:00
if db.frozenMem != nil {
db.frozenMem.incref()
}
2014-07-23 06:31:36 +00:00
return db.frozenMem
2014-07-06 12:46:48 +00:00
}
// Drop frozen memdb; assume that frozen memdb isn't nil.
2014-07-23 06:31:36 +00:00
func (db *DB) dropFrozenMem() {
db.memMu.Lock()
if err := db.s.stor.Remove(db.frozenJournalFd); err != nil {
db.logf("journal@remove removing @%d %q", db.frozenJournalFd.Num, err)
2014-07-06 12:46:48 +00:00
} else {
db.logf("journal@remove removed @%d", db.frozenJournalFd.Num)
2014-07-06 12:46:48 +00:00
}
db.frozenJournalFd = storage.FileDesc{}
2014-08-15 07:16:30 +00:00
db.frozenMem.decref()
2014-07-23 06:31:36 +00:00
db.frozenMem = nil
db.memMu.Unlock()
2014-07-06 12:46:48 +00:00
}
// Set closed flag; return true if not already closed.
2014-07-23 06:31:36 +00:00
func (db *DB) setClosed() bool {
return atomic.CompareAndSwapUint32(&db.closed, 0, 1)
2014-07-06 12:46:48 +00:00
}
// Check whether DB was closed.
2014-07-23 06:31:36 +00:00
func (db *DB) isClosed() bool {
return atomic.LoadUint32(&db.closed) != 0
2014-07-06 12:46:48 +00:00
}
// Check read ok status.
2014-07-23 06:31:36 +00:00
func (db *DB) ok() error {
if db.isClosed() {
2014-07-06 12:46:48 +00:00
return ErrClosed
}
return nil
}