2014-07-06 14:46:48 +02: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"
|
|
|
|
|
|
|
|
"github.com/syndtr/goleveldb/leveldb/journal"
|
|
|
|
"github.com/syndtr/goleveldb/leveldb/memdb"
|
2014-08-15 09:16:30 +02:00
|
|
|
"github.com/syndtr/goleveldb/leveldb/util"
|
2014-07-06 14:46:48 +02:00
|
|
|
)
|
|
|
|
|
2014-08-15 09:16:30 +02:00
|
|
|
type memDB struct {
|
|
|
|
pool *util.Pool
|
|
|
|
db *memdb.DB
|
|
|
|
ref int32
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *memDB) incref() {
|
|
|
|
atomic.AddInt32(&m.ref, 1)
|
|
|
|
}
|
|
|
|
|
|
|
|
func (m *memDB) decref() {
|
|
|
|
if ref := atomic.AddInt32(&m.ref, -1); ref == 0 {
|
|
|
|
m.pool.Put(m)
|
|
|
|
} else if ref < 0 {
|
|
|
|
panic("negative memdb ref")
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-06 14:46:48 +02:00
|
|
|
// Get latest sequence number.
|
2014-07-23 08:31:36 +02:00
|
|
|
func (db *DB) getSeq() uint64 {
|
|
|
|
return atomic.LoadUint64(&db.seq)
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Atomically adds delta to seq.
|
2014-07-23 08:31:36 +02:00
|
|
|
func (db *DB) addSeq(delta uint64) {
|
|
|
|
atomic.AddUint64(&db.seq, delta)
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Create new memdb and froze the old one; need external synchronization.
|
|
|
|
// newMem only called synchronously by the writer.
|
2014-08-15 09:16:30 +02:00
|
|
|
func (db *DB) newMem(n int) (mem *memDB, err error) {
|
2014-07-23 08:31:36 +02:00
|
|
|
num := db.s.allocFileNum()
|
|
|
|
file := db.s.getJournalFile(num)
|
2014-07-06 14:46:48 +02:00
|
|
|
w, err := file.Create()
|
|
|
|
if err != nil {
|
2014-07-23 08:31:36 +02:00
|
|
|
db.s.reuseFileNum(num)
|
2014-07-06 14:46:48 +02:00
|
|
|
return
|
|
|
|
}
|
2014-07-23 08:31:36 +02:00
|
|
|
|
|
|
|
db.memMu.Lock()
|
|
|
|
defer db.memMu.Unlock()
|
|
|
|
|
2014-08-15 09:16:30 +02:00
|
|
|
if db.frozenMem != nil {
|
|
|
|
panic("still has frozen mem")
|
|
|
|
}
|
|
|
|
|
2014-07-23 08:31:36 +02:00
|
|
|
if db.journal == nil {
|
|
|
|
db.journal = journal.NewWriter(w)
|
2014-07-06 14:46:48 +02:00
|
|
|
} else {
|
2014-07-23 08:31:36 +02:00
|
|
|
db.journal.Reset(w)
|
|
|
|
db.journalWriter.Close()
|
|
|
|
db.frozenJournalFile = db.journalFile
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
2014-07-23 08:31:36 +02:00
|
|
|
db.journalWriter = w
|
|
|
|
db.journalFile = file
|
|
|
|
db.frozenMem = db.mem
|
2014-08-15 09:16:30 +02:00
|
|
|
mem, ok := db.memPool.Get().(*memDB)
|
|
|
|
if ok && mem.db.Capacity() >= n {
|
|
|
|
mem.db.Reset()
|
|
|
|
mem.incref()
|
|
|
|
} else {
|
|
|
|
mem = &memDB{
|
|
|
|
pool: db.memPool,
|
|
|
|
db: memdb.New(db.s.icmp, maxInt(db.s.o.GetWriteBuffer(), n)),
|
|
|
|
ref: 1,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mem.incref()
|
|
|
|
db.mem = mem
|
2014-07-23 08:31:36 +02: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 14:46:48 +02:00
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get all memdbs.
|
2014-08-15 09:16:30 +02:00
|
|
|
func (db *DB) getMems() (e, f *memDB) {
|
2014-07-23 08:31:36 +02:00
|
|
|
db.memMu.RLock()
|
|
|
|
defer db.memMu.RUnlock()
|
2014-08-15 09:16:30 +02:00
|
|
|
if db.mem == nil {
|
|
|
|
panic("nil effective mem")
|
|
|
|
}
|
|
|
|
db.mem.incref()
|
|
|
|
if db.frozenMem != nil {
|
|
|
|
db.frozenMem.incref()
|
|
|
|
}
|
2014-07-23 08:31:36 +02:00
|
|
|
return db.mem, db.frozenMem
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get frozen memdb.
|
2014-08-15 09:16:30 +02:00
|
|
|
func (db *DB) getEffectiveMem() *memDB {
|
2014-07-23 08:31:36 +02:00
|
|
|
db.memMu.RLock()
|
|
|
|
defer db.memMu.RUnlock()
|
2014-08-15 09:16:30 +02:00
|
|
|
if db.mem == nil {
|
|
|
|
panic("nil effective mem")
|
|
|
|
}
|
|
|
|
db.mem.incref()
|
2014-07-23 08:31:36 +02:00
|
|
|
return db.mem
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether we has frozen memdb.
|
2014-07-23 08:31:36 +02:00
|
|
|
func (db *DB) hasFrozenMem() bool {
|
|
|
|
db.memMu.RLock()
|
|
|
|
defer db.memMu.RUnlock()
|
|
|
|
return db.frozenMem != nil
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Get frozen memdb.
|
2014-08-15 09:16:30 +02:00
|
|
|
func (db *DB) getFrozenMem() *memDB {
|
2014-07-23 08:31:36 +02:00
|
|
|
db.memMu.RLock()
|
|
|
|
defer db.memMu.RUnlock()
|
2014-08-15 09:16:30 +02:00
|
|
|
if db.frozenMem != nil {
|
|
|
|
db.frozenMem.incref()
|
|
|
|
}
|
2014-07-23 08:31:36 +02:00
|
|
|
return db.frozenMem
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Drop frozen memdb; assume that frozen memdb isn't nil.
|
2014-07-23 08:31:36 +02:00
|
|
|
func (db *DB) dropFrozenMem() {
|
|
|
|
db.memMu.Lock()
|
|
|
|
if err := db.frozenJournalFile.Remove(); err != nil {
|
|
|
|
db.logf("journal@remove removing @%d %q", db.frozenJournalFile.Num(), err)
|
2014-07-06 14:46:48 +02:00
|
|
|
} else {
|
2014-07-23 08:31:36 +02:00
|
|
|
db.logf("journal@remove removed @%d", db.frozenJournalFile.Num())
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
2014-07-23 08:31:36 +02:00
|
|
|
db.frozenJournalFile = nil
|
2014-08-15 09:16:30 +02:00
|
|
|
db.frozenMem.decref()
|
2014-07-23 08:31:36 +02:00
|
|
|
db.frozenMem = nil
|
|
|
|
db.memMu.Unlock()
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set closed flag; return true if not already closed.
|
2014-07-23 08:31:36 +02:00
|
|
|
func (db *DB) setClosed() bool {
|
|
|
|
return atomic.CompareAndSwapUint32(&db.closed, 0, 1)
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check whether DB was closed.
|
2014-07-23 08:31:36 +02:00
|
|
|
func (db *DB) isClosed() bool {
|
|
|
|
return atomic.LoadUint32(&db.closed) != 0
|
2014-07-06 14:46:48 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Check read ok status.
|
2014-07-23 08:31:36 +02:00
|
|
|
func (db *DB) ok() error {
|
|
|
|
if db.isClosed() {
|
2014-07-06 14:46:48 +02:00
|
|
|
return ErrClosed
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|