z.go 3.7 KB

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