d28f005552
Fix limit for databases other than sqlite go mod tidy && go mod vendor Remove unneeded break statements Make everything work with the new xorm version Fix xorm logging Fix lint Fix redis init Fix using id field Fix database init for testing Change default database log level Add xorm logger Use const for postgres go mod tidy Merge branch 'master' into update/xorm # Conflicts: # go.mod # go.sum # vendor/modules.txt go mod vendor Fix loading fixtures for postgres Go mod vendor1 Update xorm to version 1 Co-authored-by: kolaente <k@knt.li> Reviewed-on: https://kolaente.dev/vikunja/api/pulls/323
239 lines
4.7 KiB
Go
239 lines
4.7 KiB
Go
// 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 (
|
|
"errors"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
"github.com/syndtr/goleveldb/leveldb/journal"
|
|
"github.com/syndtr/goleveldb/leveldb/memdb"
|
|
"github.com/syndtr/goleveldb/leveldb/storage"
|
|
)
|
|
|
|
var (
|
|
errHasFrozenMem = errors.New("has frozen mem")
|
|
)
|
|
|
|
type memDB struct {
|
|
db *DB
|
|
*memdb.DB
|
|
ref int32
|
|
}
|
|
|
|
func (m *memDB) getref() int32 {
|
|
return atomic.LoadInt32(&m.ref)
|
|
}
|
|
|
|
func (m *memDB) incref() {
|
|
atomic.AddInt32(&m.ref, 1)
|
|
}
|
|
|
|
func (m *memDB) decref() {
|
|
if ref := atomic.AddInt32(&m.ref, -1); ref == 0 {
|
|
// Only put back memdb with std capacity.
|
|
if m.Capacity() == m.db.s.o.GetWriteBuffer() {
|
|
m.Reset()
|
|
m.db.mpoolPut(m.DB)
|
|
}
|
|
m.db = nil
|
|
m.DB = nil
|
|
} else if ref < 0 {
|
|
panic("negative memdb ref")
|
|
}
|
|
}
|
|
|
|
// Get latest sequence number.
|
|
func (db *DB) getSeq() uint64 {
|
|
return atomic.LoadUint64(&db.seq)
|
|
}
|
|
|
|
// Atomically adds delta to seq.
|
|
func (db *DB) addSeq(delta uint64) {
|
|
atomic.AddUint64(&db.seq, delta)
|
|
}
|
|
|
|
func (db *DB) setSeq(seq uint64) {
|
|
atomic.StoreUint64(&db.seq, seq)
|
|
}
|
|
|
|
func (db *DB) sampleSeek(ikey internalKey) {
|
|
v := db.s.version()
|
|
if v.sampleSeek(ikey) {
|
|
// Trigger table compaction.
|
|
db.compTrigger(db.tcompCmdC)
|
|
}
|
|
v.release()
|
|
}
|
|
|
|
func (db *DB) mpoolPut(mem *memdb.DB) {
|
|
if !db.isClosed() {
|
|
select {
|
|
case db.memPool <- mem:
|
|
default:
|
|
}
|
|
}
|
|
}
|
|
|
|
func (db *DB) mpoolGet(n int) *memDB {
|
|
var mdb *memdb.DB
|
|
select {
|
|
case mdb = <-db.memPool:
|
|
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,
|
|
}
|
|
}
|
|
|
|
func (db *DB) mpoolDrain() {
|
|
ticker := time.NewTicker(30 * time.Second)
|
|
for {
|
|
select {
|
|
case <-ticker.C:
|
|
select {
|
|
case <-db.memPool:
|
|
default:
|
|
}
|
|
case <-db.closeC:
|
|
ticker.Stop()
|
|
// Make sure the pool is drained.
|
|
select {
|
|
case <-db.memPool:
|
|
case <-time.After(time.Second):
|
|
}
|
|
close(db.memPool)
|
|
return
|
|
}
|
|
}
|
|
}
|
|
|
|
// Create new memdb and froze the old one; need external synchronization.
|
|
// newMem only called synchronously by the writer.
|
|
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)
|
|
if err != nil {
|
|
db.s.reuseFileNum(fd.Num)
|
|
return
|
|
}
|
|
|
|
db.memMu.Lock()
|
|
defer db.memMu.Unlock()
|
|
|
|
if db.frozenMem != nil {
|
|
return nil, errHasFrozenMem
|
|
}
|
|
|
|
if db.journal == nil {
|
|
db.journal = journal.NewWriter(w)
|
|
} else {
|
|
db.journal.Reset(w)
|
|
db.journalWriter.Close()
|
|
db.frozenJournalFd = db.journalFd
|
|
}
|
|
db.journalWriter = w
|
|
db.journalFd = fd
|
|
db.frozenMem = db.mem
|
|
mem = db.mpoolGet(n)
|
|
mem.incref() // for self
|
|
mem.incref() // for caller
|
|
db.mem = mem
|
|
// 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
|
|
return
|
|
}
|
|
|
|
// Get all memdbs.
|
|
func (db *DB) getMems() (e, f *memDB) {
|
|
db.memMu.RLock()
|
|
defer db.memMu.RUnlock()
|
|
if db.mem != nil {
|
|
db.mem.incref()
|
|
} else if !db.isClosed() {
|
|
panic("nil effective mem")
|
|
}
|
|
if db.frozenMem != nil {
|
|
db.frozenMem.incref()
|
|
}
|
|
return db.mem, db.frozenMem
|
|
}
|
|
|
|
// Get effective memdb.
|
|
func (db *DB) getEffectiveMem() *memDB {
|
|
db.memMu.RLock()
|
|
defer db.memMu.RUnlock()
|
|
if db.mem != nil {
|
|
db.mem.incref()
|
|
} else if !db.isClosed() {
|
|
panic("nil effective mem")
|
|
}
|
|
return db.mem
|
|
}
|
|
|
|
// Check whether we has frozen memdb.
|
|
func (db *DB) hasFrozenMem() bool {
|
|
db.memMu.RLock()
|
|
defer db.memMu.RUnlock()
|
|
return db.frozenMem != nil
|
|
}
|
|
|
|
// Get frozen memdb.
|
|
func (db *DB) getFrozenMem() *memDB {
|
|
db.memMu.RLock()
|
|
defer db.memMu.RUnlock()
|
|
if db.frozenMem != nil {
|
|
db.frozenMem.incref()
|
|
}
|
|
return db.frozenMem
|
|
}
|
|
|
|
// Drop frozen memdb; assume that frozen memdb isn't nil.
|
|
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)
|
|
} else {
|
|
db.logf("journal@remove removed @%d", db.frozenJournalFd.Num)
|
|
}
|
|
db.frozenJournalFd = storage.FileDesc{}
|
|
db.frozenMem.decref()
|
|
db.frozenMem = nil
|
|
db.memMu.Unlock()
|
|
}
|
|
|
|
// Clear mems ptr; used by DB.Close().
|
|
func (db *DB) clearMems() {
|
|
db.memMu.Lock()
|
|
db.mem = nil
|
|
db.frozenMem = nil
|
|
db.memMu.Unlock()
|
|
}
|
|
|
|
// Set closed flag; return true if not already closed.
|
|
func (db *DB) setClosed() bool {
|
|
return atomic.CompareAndSwapUint32(&db.closed, 0, 1)
|
|
}
|
|
|
|
// Check whether DB was closed.
|
|
func (db *DB) isClosed() bool {
|
|
return atomic.LoadUint32(&db.closed) != 0
|
|
}
|
|
|
|
// Check read ok status.
|
|
func (db *DB) ok() error {
|
|
if db.isClosed() {
|
|
return ErrClosed
|
|
}
|
|
return nil
|
|
}
|