z.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170
  1. /*
  2. * SPDX-FileCopyrightText: © 2017-2025 Istari Digital, Inc.
  3. * SPDX-License-Identifier: Apache-2.0
  4. */
  5. package z
  6. import (
  7. "context"
  8. "reflect"
  9. "sync"
  10. "github.com/cespare/xxhash/v2"
  11. )
  12. type Key interface {
  13. ~uint64 | ~string | ~[]byte | ~byte | ~int | ~uint | ~int32 | ~uint32 | ~int64
  14. }
  15. // TODO: Figure out a way to re-use memhash for the second uint64 hash,
  16. // we already know that appending bytes isn't reliable for generating a
  17. // second hash (see Ristretto PR #88).
  18. // We also know that while the Go runtime has a runtime memhash128
  19. // function, it's not possible to use it to generate [2]uint64 or
  20. // anything resembling a 128bit hash, even though that's exactly what
  21. // we need in this situation.
  22. func KeyToHash[K Key](key K) (uint64, uint64) {
  23. keyAsAny := any(key)
  24. switch k := keyAsAny.(type) {
  25. case uint64:
  26. return k, 0
  27. case string:
  28. return MemHashString(k), xxhash.Sum64String(k)
  29. case []byte:
  30. return MemHash(k), xxhash.Sum64(k)
  31. case byte:
  32. return uint64(k), 0
  33. case uint:
  34. return uint64(k), 0
  35. case int:
  36. return uint64(k), 0
  37. case int32:
  38. return uint64(k), 0
  39. case uint32:
  40. return uint64(k), 0
  41. case int64:
  42. return uint64(k), 0
  43. default:
  44. // Handle custom types with underlying types (e.g., type MyKey string)
  45. v := reflect.ValueOf(key)
  46. switch v.Kind() {
  47. case reflect.Uint64:
  48. return v.Uint(), 0
  49. case reflect.String:
  50. s := v.String()
  51. return MemHashString(s), xxhash.Sum64String(s)
  52. case reflect.Slice:
  53. if v.Type().Elem().Kind() == reflect.Uint8 {
  54. b := v.Bytes()
  55. return MemHash(b), xxhash.Sum64(b)
  56. }
  57. case reflect.Uint8:
  58. return v.Uint(), 0
  59. case reflect.Uint:
  60. return v.Uint(), 0
  61. case reflect.Int:
  62. return uint64(v.Int()), 0
  63. case reflect.Int32:
  64. return uint64(v.Int()), 0
  65. case reflect.Uint32:
  66. return v.Uint(), 0
  67. case reflect.Int64:
  68. return uint64(v.Int()), 0
  69. }
  70. panic("Key type not supported")
  71. }
  72. }
  73. var (
  74. dummyCloserChan <-chan struct{}
  75. tmpDir string
  76. )
  77. // Closer holds the two things we need to close a goroutine and wait for it to
  78. // finish: a chan to tell the goroutine to shut down, and a WaitGroup with
  79. // which to wait for it to finish shutting down.
  80. type Closer struct {
  81. waiting sync.WaitGroup
  82. ctx context.Context
  83. cancel context.CancelFunc
  84. }
  85. // SetTmpDir sets the temporary directory for the temporary buffers.
  86. func SetTmpDir(dir string) {
  87. tmpDir = dir
  88. }
  89. // NewCloser constructs a new Closer, with an initial count on the WaitGroup.
  90. func NewCloser(initial int) *Closer {
  91. ret := &Closer{}
  92. ret.ctx, ret.cancel = context.WithCancel(context.Background())
  93. ret.waiting.Add(initial)
  94. return ret
  95. }
  96. // AddRunning Add()'s delta to the WaitGroup.
  97. func (lc *Closer) AddRunning(delta int) {
  98. lc.waiting.Add(delta)
  99. }
  100. // Ctx can be used to get a context, which would automatically get cancelled when Signal is called.
  101. func (lc *Closer) Ctx() context.Context {
  102. if lc == nil {
  103. return context.Background()
  104. }
  105. return lc.ctx
  106. }
  107. // Signal signals the HasBeenClosed signal.
  108. func (lc *Closer) Signal() {
  109. // Todo(ibrahim): Change Signal to return error on next badger breaking change.
  110. lc.cancel()
  111. }
  112. // HasBeenClosed gets signaled when Signal() is called.
  113. func (lc *Closer) HasBeenClosed() <-chan struct{} {
  114. if lc == nil {
  115. return dummyCloserChan
  116. }
  117. return lc.ctx.Done()
  118. }
  119. // Done calls Done() on the WaitGroup.
  120. func (lc *Closer) Done() {
  121. if lc == nil {
  122. return
  123. }
  124. lc.waiting.Done()
  125. }
  126. // Wait waits on the WaitGroup. (It waits for NewCloser's initial value, AddRunning, and Done
  127. // calls to balance out.)
  128. func (lc *Closer) Wait() {
  129. lc.waiting.Wait()
  130. }
  131. // SignalAndWait calls Signal(), then Wait().
  132. func (lc *Closer) SignalAndWait() {
  133. lc.Signal()
  134. lc.Wait()
  135. }
  136. // ZeroOut zeroes out all the bytes in the range [start, end).
  137. func ZeroOut(dst []byte, start, end int) {
  138. if start < 0 || start >= len(dst) {
  139. return // BAD
  140. }
  141. if end >= len(dst) {
  142. end = len(dst)
  143. }
  144. if end-start <= 0 {
  145. return
  146. }
  147. Memclr(dst[start:end])
  148. // b := dst[start:end]
  149. // for i := range b {
  150. // b[i] = 0x0
  151. // }
  152. }