Skip to content

Commit

Permalink
db: add implementation warning about requirement imposed by SingleDelete
Browse files Browse the repository at this point in the history
  • Loading branch information
sumeerbhola committed Feb 14, 2025
1 parent 6edd850 commit 1463838
Show file tree
Hide file tree
Showing 2 changed files with 24 additions and 3 deletions.
4 changes: 3 additions & 1 deletion batch.go
Original file line number Diff line number Diff line change
Expand Up @@ -956,7 +956,7 @@ func (b *Batch) DeleteSizedDeferred(keyLen int, deletedValueSize uint32) *Deferr
}

// SingleDelete adds an action to the batch that single deletes the entry for key.
// See Writer.SingleDelete for more details on the semantics of SingleDelete.
// WARNING: See the detailed warning in Writer.SingleDelete before using this.
//
// It is safe to modify the contents of the arguments after SingleDelete returns.
func (b *Batch) SingleDelete(key []byte, _ *WriteOptions) error {
Expand All @@ -976,6 +976,8 @@ func (b *Batch) SingleDelete(key []byte, _ *WriteOptions) error {
// operation to the batch, except it only takes in key/value lengths instead of
// complete slices, letting the caller encode into those objects and then call
// Finish() on the returned object.
//
// WARNING: See the detailed warning in Writer.SingleDelete before using this.
func (b *Batch) SingleDeleteDeferred(keyLen int) *DeferredBatchOp {
b.prepareDeferredKeyRecord(keyLen, InternalKeyKindSingleDelete)
b.deferredOp.index = b.index
Expand Down
23 changes: 21 additions & 2 deletions db.go
Original file line number Diff line number Diff line change
Expand Up @@ -139,8 +139,25 @@ type Writer interface {
// properly. Only use if you have a workload where the performance gain is critical and you
// can guarantee that a record is written once and then deleted once.
//
// SingleDelete is internally transformed into a Delete if the most recent record for a key is either
// a Merge or Delete record.
// Note that SINGLEDEL, SET, SINGLEDEL, SET, DEL/RANGEDEL, ... from most
// recent to older will work as intended since there is a single SET
// sandwiched between SINGLEDEL/DEL/RANGEDEL.
//
// IMPLEMENTATION WARNING: By offering SingleDelete, Pebble must guarantee
// that there is no duplication of writes inside Pebble. That is, idempotent
// application of writes is insufficient. For example, if a SET operation
// gets duplicated inside Pebble, resulting in say SET#20 and SET#17, the
// caller may issue a SINGLEDEL#25 and it will not have the desired effect.
// This guarantee is partially achieved by ensuring that a WAL and a
// flushable are usually in one-to-one correspondence, and atomically
// updating the MANIFEST when the flushable is flushed (which ensures the
// WAL will never be replayed). There is one exception: a flushableBatch is
// written to the end of the WAL that it shares with the preceding memtable.
// This is safe because the memtable and the flushableBatch are part of the
// same flush (see DB.flush1 where this invariant is maintained). If the
// memtable were to be flushed without the flushableBatch, the WAL cannot
// yet be deleted and if a crash happened, the WAL would be replayed despite
// the memtable already being flushed.
//
// It is safe to modify the contents of the arguments after SingleDelete returns.
SingleDelete(key []byte, o *WriteOptions) error
Expand Down Expand Up @@ -682,6 +699,8 @@ func (d *DB) DeleteSized(key []byte, valueSize uint32, opts *WriteOptions) error
// SingleDelete adds an action to the batch that single deletes the entry for key.
// See Writer.SingleDelete for more details on the semantics of SingleDelete.
//
// WARNING: See the detailed warning in Writer.SingleDelete before using this.
//
// It is safe to modify the contents of the arguments after SingleDelete returns.
func (d *DB) SingleDelete(key []byte, opts *WriteOptions) error {
b := newBatch(d)
Expand Down

0 comments on commit 1463838

Please sign in to comment.