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 }