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  }