// Write apply the given batch to the DB. The batch will be applied // sequentially. // // It is safe to modify the contents of the arguments after Write returns. func (d *DB) Write(b *Batch, wo *opt.WriteOptions) (err error) { err = d.ok() if err != nil || b == nil || b.len() == 0 { return } b.init(wo.GetSync()) // The write happen synchronously. select { case _, _ = <-d.closeCh: return ErrClosed case d.writeCh <- b: return <-d.writeAckCh case d.writeLockCh <- struct{}{}: } merged := 0 defer func() { <-d.writeLockCh for i := 0; i < merged; i++ { d.writeAckCh <- err } }() mem, err := d.flush() if err != nil { return } // Calculate maximum size of the batch. m := 1 << 20 if x := b.size(); x <= 128<<10 { m = x + (128 << 10) } // Merge with other batch. drain: for b.size() <= m && !b.sync { select { case nb := <-d.writeCh: b.append(nb) merged++ default: break drain } } // Set batch first seq number relative from last seq. b.seq = d.seq + 1 // Write journal concurrently if it is large enough. if b.size() >= (128 << 10) { // Push the write batch to the journal writer select { case _, _ = <-d.closeCh: err = ErrClosed return case d.journalCh <- b: // Write into memdb b.memReplay(mem) } // Wait for journal writer select { case _, _ = <-d.closeCh: err = ErrClosed return case err = <-d.journalAckCh: if err != nil { // Revert memdb if error detected b.revertMemReplay(mem) return } } } else { err = d.doWriteJournal(b) if err != nil { return } b.memReplay(mem) } // Set last seq number. d.addSeq(uint64(b.len())) return }
// Write apply the given batch to the DB. The batch will be applied // sequentially. // // It is safe to modify the contents of the arguments after Write returns. func (db *DB) Write(b *Batch, wo *opt.WriteOptions) (err error) { err = db.ok() if err != nil || b == nil || b.len() == 0 { return } b.init(wo.GetSync()) // The write happen synchronously. retry: select { case db.writeC <- b: if <-db.writeMergedC { return <-db.writeAckC } goto retry case db.writeLockC <- struct{}{}: case _, _ = <-db.closeC: return ErrClosed } merged := 0 defer func() { <-db.writeLockC for i := 0; i < merged; i++ { db.writeAckC <- err } }() mem, memFree, err := db.flush(b.size()) if err != nil { return } // Calculate maximum size of the batch. m := 1 << 20 if x := b.size(); x <= 128<<10 { m = x + (128 << 10) } m = minInt(m, memFree) // Merge with other batch. drain: for b.size() < m && !b.sync { select { case nb := <-db.writeC: if b.size()+nb.size() <= m { b.append(nb) db.writeMergedC <- true merged++ } else { db.writeMergedC <- false break drain } default: break drain } } // Set batch first seq number relative from last seq. b.seq = db.seq + 1 // Write journal concurrently if it is large enough. if b.size() >= (128 << 10) { // Push the write batch to the journal writer select { case _, _ = <-db.closeC: err = ErrClosed return case db.journalC <- b: // Write into memdb b.memReplay(mem) } // Wait for journal writer select { case _, _ = <-db.closeC: err = ErrClosed return case err = <-db.journalAckC: if err != nil { // Revert memdb if error detected b.revertMemReplay(mem) return } } } else { err = db.writeJournal(b) if err != nil { return } b.memReplay(mem) } // Set last seq number. db.addSeq(uint64(b.len())) if b.size() >= memFree { db.rotateMem(0) } return }