github.com/petermattis/pebble@v0.0.0-20190905164901-ab51a2166067/tool/util.go (about)

     1  // Copyright 2019 The LevelDB-Go and Pebble Authors. All rights reserved. Use
     2  // of this source code is governed by a BSD-style license that can be found in
     3  // the LICENSE file.
     4  
     5  package tool
     6  
     7  import (
     8  	"encoding/hex"
     9  	"fmt"
    10  	"io"
    11  	"os"
    12  	"strconv"
    13  	"strings"
    14  	"time"
    15  
    16  	"github.com/petermattis/pebble/internal/base"
    17  )
    18  
    19  var stdout = io.Writer(os.Stdout)
    20  var stderr = io.Writer(os.Stderr)
    21  var osExit = os.Exit
    22  var timeNow = time.Now
    23  
    24  type key []byte
    25  
    26  func (k *key) String() string {
    27  	return string(*k)
    28  }
    29  
    30  func (k *key) Type() string {
    31  	return "key"
    32  }
    33  
    34  func (k *key) Set(v string) error {
    35  	switch {
    36  	case strings.HasPrefix(v, "hex:"):
    37  		v = strings.TrimPrefix(v, "hex:")
    38  		b, err := hex.DecodeString(v)
    39  		if err != nil {
    40  			return err
    41  		}
    42  		*k = key(b)
    43  
    44  	case strings.HasPrefix(v, "raw:"):
    45  		*k = key(strings.TrimPrefix(v, "raw:"))
    46  
    47  	default:
    48  		*k = key(v)
    49  	}
    50  	return nil
    51  }
    52  
    53  type formatter struct {
    54  	spec string
    55  	fn   func(w io.Writer, v []byte)
    56  }
    57  
    58  func (f *formatter) String() string {
    59  	return f.spec
    60  }
    61  
    62  func (f *formatter) Type() string {
    63  	return "formatter"
    64  }
    65  
    66  func (f *formatter) Set(spec string) error {
    67  	f.spec = spec
    68  	switch spec {
    69  	case "null":
    70  		f.fn = formatNull
    71  	case "quoted":
    72  		f.fn = formatQuoted
    73  	case "size":
    74  		f.fn = formatSize
    75  	default:
    76  		if strings.Count(spec, "%") != 1 {
    77  			return fmt.Errorf("unknown formatter: %q", spec)
    78  		}
    79  		f.fn = func(w io.Writer, v []byte) {
    80  			fmt.Fprintf(w, f.spec, v)
    81  		}
    82  	}
    83  	return nil
    84  }
    85  
    86  func (f *formatter) mustSet(spec string) {
    87  	if err := f.Set(spec); err != nil {
    88  		panic(err)
    89  	}
    90  }
    91  
    92  func formatNull(w io.Writer, v []byte) {
    93  }
    94  
    95  func formatQuoted(w io.Writer, v []byte) {
    96  	q := strconv.AppendQuote(make([]byte, 0, len(v)), string(v))
    97  	q = q[1 : len(q)-1]
    98  	w.Write(q)
    99  }
   100  
   101  func formatSize(w io.Writer, v []byte) {
   102  	fmt.Fprintf(w, "<%d>", len(v))
   103  }
   104  
   105  func formatKey(w io.Writer, fmtKey formatter, key *base.InternalKey) bool {
   106  	if fmtKey.spec == "null" {
   107  		return false
   108  	}
   109  	fmtKey.fn(w, key.UserKey)
   110  	fmt.Fprintf(w, "#%d,%d", key.SeqNum(), key.Kind())
   111  	return true
   112  }
   113  
   114  func formatKeyRange(w io.Writer, fmtKey formatter, start, end *base.InternalKey) {
   115  	if fmtKey.spec == "null" {
   116  		return
   117  	}
   118  	w.Write([]byte{'['})
   119  	formatKey(w, fmtKey, start)
   120  	w.Write([]byte{'-'})
   121  	formatKey(w, fmtKey, end)
   122  	w.Write([]byte{']'})
   123  }
   124  
   125  func formatKeyValue(
   126  	w io.Writer, fmtKey formatter, fmtValue formatter, key *base.InternalKey, value []byte,
   127  ) {
   128  	if key.Kind() == base.InternalKeyKindRangeDelete {
   129  		if fmtKey.spec != "null" {
   130  			fmtKey.fn(w, key.UserKey)
   131  			w.Write([]byte{'-'})
   132  			fmtKey.fn(w, value)
   133  			fmt.Fprintf(w, "#%d,%d", key.SeqNum(), key.Kind())
   134  		}
   135  	} else {
   136  		needDelimiter := formatKey(w, fmtKey, key)
   137  		if fmtValue.spec != "null" {
   138  			if needDelimiter {
   139  				w.Write([]byte{' '})
   140  			}
   141  			fmtValue.fn(stdout, value)
   142  		}
   143  	}
   144  	w.Write([]byte{'\n'})
   145  }