github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/syndtr/goleveldb/leveldb/db_write.go (about) 1 // Copyright (c) 2012, 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 "time" 11 12 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/memdb" 13 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/opt" 14 "github.com/insionng/yougam/libraries/syndtr/goleveldb/leveldb/util" 15 ) 16 17 func (db *DB) writeJournal(b *Batch) error { 18 w, err := db.journal.Next() 19 if err != nil { 20 return err 21 } 22 if _, err := w.Write(b.encode()); err != nil { 23 return err 24 } 25 if err := db.journal.Flush(); err != nil { 26 return err 27 } 28 if b.sync { 29 return db.journalWriter.Sync() 30 } 31 return nil 32 } 33 34 func (db *DB) jWriter() { 35 defer db.closeW.Done() 36 for { 37 select { 38 case b := <-db.journalC: 39 if b != nil { 40 db.journalAckC <- db.writeJournal(b) 41 } 42 case _, _ = <-db.closeC: 43 return 44 } 45 } 46 } 47 48 func (db *DB) rotateMem(n int, wait bool) (mem *memDB, err error) { 49 // Wait for pending memdb compaction. 50 err = db.compTriggerWait(db.mcompCmdC) 51 if err != nil { 52 return 53 } 54 55 // Create new memdb and journal. 56 mem, err = db.newMem(n) 57 if err != nil { 58 return 59 } 60 61 // Schedule memdb compaction. 62 if wait { 63 err = db.compTriggerWait(db.mcompCmdC) 64 } else { 65 db.compTrigger(db.mcompCmdC) 66 } 67 return 68 } 69 70 func (db *DB) flush(n int) (mdb *memDB, mdbFree int, err error) { 71 delayed := false 72 flush := func() (retry bool) { 73 v := db.s.version() 74 defer v.release() 75 mdb = db.getEffectiveMem() 76 defer func() { 77 if retry { 78 mdb.decref() 79 mdb = nil 80 } 81 }() 82 mdbFree = mdb.Free() 83 switch { 84 case v.tLen(0) >= db.s.o.GetWriteL0SlowdownTrigger() && !delayed: 85 delayed = true 86 time.Sleep(time.Millisecond) 87 case mdbFree >= n: 88 return false 89 case v.tLen(0) >= db.s.o.GetWriteL0PauseTrigger(): 90 delayed = true 91 err = db.compTriggerWait(db.tcompCmdC) 92 if err != nil { 93 return false 94 } 95 default: 96 // Allow memdb to grow if it has no entry. 97 if mdb.Len() == 0 { 98 mdbFree = n 99 } else { 100 mdb.decref() 101 mdb, err = db.rotateMem(n, false) 102 if err == nil { 103 mdbFree = mdb.Free() 104 } else { 105 mdbFree = 0 106 } 107 } 108 return false 109 } 110 return true 111 } 112 start := time.Now() 113 for flush() { 114 } 115 if delayed { 116 db.writeDelay += time.Since(start) 117 db.writeDelayN++ 118 } else if db.writeDelayN > 0 { 119 db.logf("db@write was delayed N·%d T·%v", db.writeDelayN, db.writeDelay) 120 db.writeDelay = 0 121 db.writeDelayN = 0 122 } 123 return 124 } 125 126 // Write apply the given batch to the DB. The batch will be applied 127 // sequentially. 128 // 129 // It is safe to modify the contents of the arguments after Write returns. 130 func (db *DB) Write(b *Batch, wo *opt.WriteOptions) (err error) { 131 err = db.ok() 132 if err != nil || b == nil || b.Len() == 0 { 133 return 134 } 135 136 b.init(wo.GetSync() && !db.s.o.GetNoSync()) 137 138 if b.size() > db.s.o.GetWriteBuffer() && !db.s.o.GetDisableLargeBatchTransaction() { 139 // Writes using transaction. 140 tr, err1 := db.OpenTransaction() 141 if err1 != nil { 142 return err1 143 } 144 if err1 := tr.Write(b, wo); err1 != nil { 145 tr.Discard() 146 return err1 147 } 148 return tr.Commit() 149 } 150 151 // The write happen synchronously. 152 select { 153 case db.writeC <- b: 154 if <-db.writeMergedC { 155 return <-db.writeAckC 156 } 157 // Continue, the write lock already acquired by previous writer 158 // and handed out to us. 159 case db.writeLockC <- struct{}{}: 160 case err = <-db.compPerErrC: 161 return 162 case _, _ = <-db.closeC: 163 return ErrClosed 164 } 165 166 merged := 0 167 danglingMerge := false 168 defer func() { 169 for i := 0; i < merged; i++ { 170 db.writeAckC <- err 171 } 172 if danglingMerge { 173 // Only one dangling merge at most, so this is safe. 174 db.writeMergedC <- false 175 } else { 176 <-db.writeLockC 177 } 178 }() 179 180 mdb, mdbFree, err := db.flush(b.size()) 181 if err != nil { 182 return 183 } 184 defer mdb.decref() 185 186 // Calculate maximum size of the batch. 187 m := 1 << 20 188 if x := b.size(); x <= 128<<10 { 189 m = x + (128 << 10) 190 } 191 m = minInt(m, mdbFree) 192 193 // Merge with other batch. 194 drain: 195 for b.size() < m && !b.sync { 196 select { 197 case nb := <-db.writeC: 198 if b.size()+nb.size() <= m { 199 b.append(nb) 200 db.writeMergedC <- true 201 merged++ 202 } else { 203 danglingMerge = true 204 break drain 205 } 206 default: 207 break drain 208 } 209 } 210 211 // Set batch first seq number relative from last seq. 212 b.seq = db.seq + 1 213 214 // Write journal concurrently if it is large enough. 215 if b.size() >= (128 << 10) { 216 // Push the write batch to the journal writer 217 select { 218 case db.journalC <- b: 219 // Write into memdb 220 if berr := b.memReplay(mdb.DB); berr != nil { 221 panic(berr) 222 } 223 case err = <-db.compPerErrC: 224 return 225 case _, _ = <-db.closeC: 226 err = ErrClosed 227 return 228 } 229 // Wait for journal writer 230 select { 231 case err = <-db.journalAckC: 232 if err != nil { 233 // Revert memdb if error detected 234 if berr := b.revertMemReplay(mdb.DB); berr != nil { 235 panic(berr) 236 } 237 return 238 } 239 case _, _ = <-db.closeC: 240 err = ErrClosed 241 return 242 } 243 } else { 244 err = db.writeJournal(b) 245 if err != nil { 246 return 247 } 248 if berr := b.memReplay(mdb.DB); berr != nil { 249 panic(berr) 250 } 251 } 252 253 // Set last seq number. 254 db.addSeq(uint64(b.Len())) 255 256 if b.size() >= mdbFree { 257 db.rotateMem(0, false) 258 } 259 return 260 } 261 262 // Put sets the value for the given key. It overwrites any previous value 263 // for that key; a DB is not a multi-map. 264 // 265 // It is safe to modify the contents of the arguments after Put returns. 266 func (db *DB) Put(key, value []byte, wo *opt.WriteOptions) error { 267 b := new(Batch) 268 b.Put(key, value) 269 return db.Write(b, wo) 270 } 271 272 // Delete deletes the value for the given key. 273 // 274 // It is safe to modify the contents of the arguments after Delete returns. 275 func (db *DB) Delete(key []byte, wo *opt.WriteOptions) error { 276 b := new(Batch) 277 b.Delete(key) 278 return db.Write(b, wo) 279 } 280 281 func isMemOverlaps(icmp *iComparer, mem *memdb.DB, min, max []byte) bool { 282 iter := mem.NewIterator(nil) 283 defer iter.Release() 284 return (max == nil || (iter.First() && icmp.uCompare(max, internalKey(iter.Key()).ukey()) >= 0)) && 285 (min == nil || (iter.Last() && icmp.uCompare(min, internalKey(iter.Key()).ukey()) <= 0)) 286 } 287 288 // CompactRange compacts the underlying DB for the given key range. 289 // In particular, deleted and overwritten versions are discarded, 290 // and the data is rearranged to reduce the cost of operations 291 // needed to access the data. This operation should typically only 292 // be invoked by users who understand the underlying implementation. 293 // 294 // A nil Range.Start is treated as a key before all keys in the DB. 295 // And a nil Range.Limit is treated as a key after all keys in the DB. 296 // Therefore if both is nil then it will compact entire DB. 297 func (db *DB) CompactRange(r util.Range) error { 298 if err := db.ok(); err != nil { 299 return err 300 } 301 302 // Lock writer. 303 select { 304 case db.writeLockC <- struct{}{}: 305 case err := <-db.compPerErrC: 306 return err 307 case _, _ = <-db.closeC: 308 return ErrClosed 309 } 310 311 // Check for overlaps in memdb. 312 mdb := db.getEffectiveMem() 313 defer mdb.decref() 314 if isMemOverlaps(db.s.icmp, mdb.DB, r.Start, r.Limit) { 315 // Memdb compaction. 316 if _, err := db.rotateMem(0, false); err != nil { 317 <-db.writeLockC 318 return err 319 } 320 <-db.writeLockC 321 if err := db.compTriggerWait(db.mcompCmdC); err != nil { 322 return err 323 } 324 } else { 325 <-db.writeLockC 326 } 327 328 // Table compaction. 329 return db.compTriggerRange(db.tcompCmdC, -1, r.Start, r.Limit) 330 } 331 332 // SetReadOnly makes DB read-only. It will stay read-only until reopened. 333 func (db *DB) SetReadOnly() error { 334 if err := db.ok(); err != nil { 335 return err 336 } 337 338 // Lock writer. 339 select { 340 case db.writeLockC <- struct{}{}: 341 db.compWriteLocking = true 342 case err := <-db.compPerErrC: 343 return err 344 case _, _ = <-db.closeC: 345 return ErrClosed 346 } 347 348 // Set compaction read-only. 349 select { 350 case db.compErrSetC <- ErrReadOnly: 351 case perr := <-db.compPerErrC: 352 return perr 353 case _, _ = <-db.closeC: 354 return ErrClosed 355 } 356 357 return nil 358 }