github.com/outcaste-io/ristretto@v0.2.3/z/z.go (about)

     1  /*
     2   * Copyright 2019 Dgraph Labs, Inc. and Contributors
     3   *
     4   * Licensed under the Apache License, Version 2.0 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   *
     8   *     http://www.apache.org/licenses/LICENSE-2.0
     9   *
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  package z
    18  
    19  import (
    20  	"context"
    21  	"fmt"
    22  	"os"
    23  	"sync"
    24  
    25  	"github.com/cespare/xxhash/v2"
    26  )
    27  
    28  // TODO: Figure out a way to re-use memhash for the second uint64 hash, we
    29  //       already know that appending bytes isn't reliable for generating a
    30  //       second hash (see Ristretto PR #88).
    31  //
    32  //       We also know that while the Go runtime has a runtime memhash128
    33  //       function, it's not possible to use it to generate [2]uint64 or
    34  //       anything resembling a 128bit hash, even though that's exactly what
    35  //       we need in this situation.
    36  func KeyToHash(key interface{}) (uint64, uint64) {
    37  	if key == nil {
    38  		return 0, 0
    39  	}
    40  	switch k := key.(type) {
    41  	case uint64:
    42  		return k, 0
    43  	case string:
    44  		return MemHashString(k), xxhash.Sum64String(k)
    45  	case []byte:
    46  		return MemHash(k), xxhash.Sum64(k)
    47  	case byte:
    48  		return uint64(k), 0
    49  	case int:
    50  		return uint64(k), 0
    51  	case int32:
    52  		return uint64(k), 0
    53  	case uint32:
    54  		return uint64(k), 0
    55  	case int64:
    56  		return uint64(k), 0
    57  	default:
    58  		panic("Key type not supported")
    59  	}
    60  }
    61  
    62  var (
    63  	dummyCloserChan <-chan struct{}
    64  	tmpDir          string
    65  )
    66  
    67  // Closer holds the two things we need to close a goroutine and wait for it to
    68  // finish: a chan to tell the goroutine to shut down, and a WaitGroup with
    69  // which to wait for it to finish shutting down.
    70  type Closer struct {
    71  	waiting sync.WaitGroup
    72  
    73  	ctx    context.Context
    74  	cancel context.CancelFunc
    75  }
    76  
    77  // SetTmpDir sets the temporary directory for the temporary buffers.
    78  func SetTmpDir(dir string) {
    79  	tmpDir = dir
    80  }
    81  
    82  // NewCloser constructs a new Closer, with an initial count on the WaitGroup.
    83  func NewCloser(initial int) *Closer {
    84  	ret := &Closer{}
    85  	ret.ctx, ret.cancel = context.WithCancel(context.Background())
    86  	ret.waiting.Add(initial)
    87  	return ret
    88  }
    89  
    90  // AddRunning Add()'s delta to the WaitGroup.
    91  func (lc *Closer) AddRunning(delta int) {
    92  	lc.waiting.Add(delta)
    93  }
    94  
    95  // Ctx can be used to get a context, which would automatically get cancelled when Signal is called.
    96  func (lc *Closer) Ctx() context.Context {
    97  	if lc == nil {
    98  		return context.Background()
    99  	}
   100  	return lc.ctx
   101  }
   102  
   103  // Signal signals the HasBeenClosed signal.
   104  func (lc *Closer) Signal() {
   105  	// Todo(ibrahim): Change Signal to return error on next badger breaking change.
   106  	lc.cancel()
   107  }
   108  
   109  // HasBeenClosed gets signaled when Signal() is called.
   110  func (lc *Closer) HasBeenClosed() <-chan struct{} {
   111  	if lc == nil {
   112  		return dummyCloserChan
   113  	}
   114  	return lc.ctx.Done()
   115  }
   116  
   117  // Done calls Done() on the WaitGroup.
   118  func (lc *Closer) Done() {
   119  	if lc == nil {
   120  		return
   121  	}
   122  	lc.waiting.Done()
   123  }
   124  
   125  // Wait waits on the WaitGroup. (It waits for NewCloser's initial value, AddRunning, and Done
   126  // calls to balance out.)
   127  func (lc *Closer) Wait() {
   128  	lc.waiting.Wait()
   129  }
   130  
   131  // SignalAndWait calls Signal(), then Wait().
   132  func (lc *Closer) SignalAndWait() {
   133  	lc.Signal()
   134  	lc.Wait()
   135  }
   136  
   137  // ZeroOut zeroes out all the bytes in the range [start, end).
   138  func ZeroOut(dst []byte, start, end int) {
   139  	if start < 0 || start >= len(dst) {
   140  		return // BAD
   141  	}
   142  	if end >= len(dst) {
   143  		end = len(dst)
   144  	}
   145  	if end-start <= 0 {
   146  		return
   147  	}
   148  	Memclr(dst[start:end])
   149  	// b := dst[start:end]
   150  	// for i := range b {
   151  	// 	b[i] = 0x0
   152  	// }
   153  }
   154  
   155  func fatal(args ...interface{}) {
   156  	defer os.Exit(1)
   157  	panic(fmt.Sprint(args...))
   158  }
   159  
   160  func fatalf(format string, args ...interface{}) {
   161  	defer os.Exit(1)
   162  	panic(fmt.Sprintf(format, args...))
   163  }