github.com/cockroachdb/cockroach@v20.2.0-alpha.1+incompatible/pkg/storage/sst_writer.go (about)

     1  // Copyright 2019 The Cockroach Authors.
     2  //
     3  // Use of this software is governed by the Business Source License
     4  // included in the file licenses/BSL.txt.
     5  //
     6  // As of the Change Date specified in that file, in accordance with
     7  // the Business Source License, use of this software will be governed
     8  // by the Apache License, Version 2.0, included in the file
     9  // licenses/APL.txt.
    10  
    11  package storage
    12  
    13  import (
    14  	"bytes"
    15  	"io"
    16  
    17  	"github.com/cockroachdb/cockroach/pkg/roachpb"
    18  	"github.com/cockroachdb/errors"
    19  	"github.com/cockroachdb/pebble/sstable"
    20  )
    21  
    22  // SSTWriter writes SSTables.
    23  type SSTWriter struct {
    24  	fw *sstable.Writer
    25  	f  writeCloseSyncer
    26  	// DataSize tracks the total key and value bytes added so far.
    27  	DataSize int64
    28  	scratch  []byte
    29  }
    30  
    31  // writeCloseSyncer interface copied from pebble.sstable.
    32  type writeCloseSyncer interface {
    33  	io.WriteCloser
    34  	Sync() error
    35  }
    36  
    37  // MakeBackupSSTWriter creates a new SSTWriter tailored for backup SSTs. These
    38  // SSTs have bloom filters disabled and format set to LevelDB.
    39  func MakeBackupSSTWriter(f writeCloseSyncer) SSTWriter {
    40  	opts := DefaultPebbleOptions().MakeWriterOptions(0)
    41  	opts.TableFormat = sstable.TableFormatLevelDB
    42  	// Disable bloom filters to produce SSTs matching those from
    43  	// RocksDBSstFileWriter.
    44  	opts.FilterPolicy = nil
    45  	opts.MergerName = "nullptr"
    46  	sst := sstable.NewWriter(f, opts)
    47  	return SSTWriter{fw: sst, f: f}
    48  }
    49  
    50  // MakeIngestionSSTWriter creates a new SSTWriter tailored for ingestion SSTs.
    51  // These SSTs have bloom filters enabled (as set in DefaultPebbleOptions) and
    52  // format set to RocksDBv2.
    53  func MakeIngestionSSTWriter(f writeCloseSyncer) SSTWriter {
    54  	opts := DefaultPebbleOptions().MakeWriterOptions(0)
    55  	opts.TableFormat = sstable.TableFormatRocksDBv2
    56  	opts.MergerName = "nullptr"
    57  	sst := sstable.NewWriter(f, opts)
    58  	return SSTWriter{fw: sst, f: f}
    59  }
    60  
    61  // Finish finalizes the writer and returns the constructed file's contents,
    62  // since the last call to Truncate (if any). At least one kv entry must have been added.
    63  func (fw *SSTWriter) Finish() error {
    64  	if fw.fw == nil {
    65  		return errors.New("cannot call Finish on a closed writer")
    66  	}
    67  	if err := fw.fw.Close(); err != nil {
    68  		return err
    69  	}
    70  	fw.fw = nil
    71  	return nil
    72  }
    73  
    74  // ClearRange implements the Writer interface.
    75  func (fw *SSTWriter) ClearRange(start, end MVCCKey) error {
    76  	if fw.fw == nil {
    77  		return errors.New("cannot call ClearRange on a closed writer")
    78  	}
    79  	fw.DataSize += int64(len(start.Key)) + int64(len(end.Key))
    80  	fw.scratch = EncodeKeyToBuf(fw.scratch[:0], start)
    81  	return fw.fw.DeleteRange(fw.scratch, EncodeKey(end))
    82  }
    83  
    84  // Put puts a kv entry into the sstable being built. An error is returned if it
    85  // is not greater than any previously added entry (according to the comparator
    86  // configured during writer creation). `Close` cannot have been called.
    87  func (fw *SSTWriter) Put(key MVCCKey, value []byte) error {
    88  	if fw.fw == nil {
    89  		return errors.New("cannot call Put on a closed writer")
    90  	}
    91  	fw.DataSize += int64(len(key.Key)) + int64(len(value))
    92  	fw.scratch = EncodeKeyToBuf(fw.scratch[:0], key)
    93  	return fw.fw.Set(fw.scratch, value)
    94  }
    95  
    96  // ApplyBatchRepr implements the Writer interface.
    97  func (fw *SSTWriter) ApplyBatchRepr(repr []byte, sync bool) error {
    98  	panic("unimplemented")
    99  }
   100  
   101  // Clear implements the Writer interface.
   102  func (fw *SSTWriter) Clear(key MVCCKey) error {
   103  	if fw.fw == nil {
   104  		return errors.New("cannot call Clear on a closed writer")
   105  	}
   106  	fw.scratch = EncodeKeyToBuf(fw.scratch[:0], key)
   107  	fw.DataSize += int64(len(key.Key))
   108  	return fw.fw.Delete(fw.scratch)
   109  }
   110  
   111  // SingleClear implements the Writer interface.
   112  func (fw *SSTWriter) SingleClear(key MVCCKey) error {
   113  	panic("unimplemented")
   114  }
   115  
   116  // ClearIterRange implements the Writer interface.
   117  func (fw *SSTWriter) ClearIterRange(iter Iterator, start, end roachpb.Key) error {
   118  	if fw.fw == nil {
   119  		return errors.New("cannot call ClearIterRange on a closed writer")
   120  	}
   121  
   122  	// Set an upper bound on the iterator. This is okay because all calls to
   123  	// ClearIterRange are with throwaway iterators, so there should be no new
   124  	// side effects.
   125  	iter.SetUpperBound(end)
   126  	iter.SeekGE(MakeMVCCMetadataKey(start))
   127  
   128  	valid, err := iter.Valid()
   129  	for valid && err == nil {
   130  		key := iter.UnsafeKey()
   131  		fw.scratch = EncodeKeyToBuf(fw.scratch[:0], key)
   132  		fw.DataSize += int64(len(key.Key))
   133  		if err := fw.fw.Delete(fw.scratch); err != nil {
   134  			return err
   135  		}
   136  
   137  		iter.Next()
   138  		valid, err = iter.Valid()
   139  	}
   140  	return err
   141  }
   142  
   143  // Merge implements the Writer interface.
   144  func (fw *SSTWriter) Merge(key MVCCKey, value []byte) error {
   145  	if fw.fw == nil {
   146  		return errors.New("cannot call Merge on a closed writer")
   147  	}
   148  	fw.DataSize += int64(len(key.Key)) + int64(len(value))
   149  	fw.scratch = EncodeKeyToBuf(fw.scratch[:0], key)
   150  	return fw.fw.Merge(fw.scratch, value)
   151  }
   152  
   153  // LogData implements the Writer interface.
   154  func (fw *SSTWriter) LogData(data []byte) error {
   155  	// No-op.
   156  	return nil
   157  }
   158  
   159  // LogLogicalOp implements the Writer interface.
   160  func (fw *SSTWriter) LogLogicalOp(op MVCCLogicalOpType, details MVCCLogicalOpDetails) {
   161  	// No-op.
   162  }
   163  
   164  // Close finishes and frees memory and other resources. Close is idempotent.
   165  func (fw *SSTWriter) Close() {
   166  	if fw.fw == nil {
   167  		return
   168  	}
   169  	// pebble.Writer *does* return interesting errors from Close... but normally
   170  	// we already called its Close() in Finish() and we no-op here. Thus the only
   171  	// time we expect to be here is in a deferred Close(), in which case the caller
   172  	// probably is already returning some other error, so returning one from this
   173  	// method just makes for messy defers.
   174  	_ = fw.fw.Close()
   175  	fw.fw = nil
   176  }
   177  
   178  // MemFile is a file-like struct that buffers all data written to it in memory.
   179  // Implements the writeCloseSyncer interface and is intended for use with
   180  // SSTWriter.
   181  type MemFile struct {
   182  	bytes.Buffer
   183  }
   184  
   185  // Close implements the writeCloseSyncer interface.
   186  func (*MemFile) Close() error {
   187  	return nil
   188  }
   189  
   190  // Sync implements the writeCloseSyncer interface.
   191  func (*MemFile) Sync() error {
   192  	return nil
   193  }
   194  
   195  // Data returns the in-memory buffer behind this MemFile.
   196  func (f *MemFile) Data() []byte {
   197  	return f.Bytes()
   198  }