arena.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136
  1. /*
  2. * Copyright 2017 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 skl
  17. import (
  18. "sync/atomic"
  19. "unsafe"
  20. "github.com/dgraph-io/badger/y"
  21. )
  22. const (
  23. offsetSize = int(unsafe.Sizeof(uint32(0)))
  24. // Always align nodes on 64-bit boundaries, even on 32-bit architectures,
  25. // so that the node.value field is 64-bit aligned. This is necessary because
  26. // node.getValueOffset uses atomic.LoadUint64, which expects its input
  27. // pointer to be 64-bit aligned.
  28. nodeAlign = int(unsafe.Sizeof(uint64(0))) - 1
  29. )
  30. // Arena should be lock-free.
  31. type Arena struct {
  32. n uint32
  33. buf []byte
  34. }
  35. // newArena returns a new arena.
  36. func newArena(n int64) *Arena {
  37. // Don't store data at position 0 in order to reserve offset=0 as a kind
  38. // of nil pointer.
  39. out := &Arena{
  40. n: 1,
  41. buf: make([]byte, n),
  42. }
  43. return out
  44. }
  45. func (s *Arena) size() int64 {
  46. return int64(atomic.LoadUint32(&s.n))
  47. }
  48. func (s *Arena) reset() {
  49. atomic.StoreUint32(&s.n, 0)
  50. }
  51. // putNode allocates a node in the arena. The node is aligned on a pointer-sized
  52. // boundary. The arena offset of the node is returned.
  53. func (s *Arena) putNode(height int) uint32 {
  54. // Compute the amount of the tower that will never be used, since the height
  55. // is less than maxHeight.
  56. unusedSize := (maxHeight - height) * offsetSize
  57. // Pad the allocation with enough bytes to ensure pointer alignment.
  58. l := uint32(MaxNodeSize - unusedSize + nodeAlign)
  59. n := atomic.AddUint32(&s.n, l)
  60. y.AssertTruef(int(n) <= len(s.buf),
  61. "Arena too small, toWrite:%d newTotal:%d limit:%d",
  62. l, n, len(s.buf))
  63. // Return the aligned offset.
  64. m := (n - l + uint32(nodeAlign)) & ^uint32(nodeAlign)
  65. return m
  66. }
  67. // Put will *copy* val into arena. To make better use of this, reuse your input
  68. // val buffer. Returns an offset into buf. User is responsible for remembering
  69. // size of val. We could also store this size inside arena but the encoding and
  70. // decoding will incur some overhead.
  71. func (s *Arena) putVal(v y.ValueStruct) uint32 {
  72. l := uint32(v.EncodedSize())
  73. n := atomic.AddUint32(&s.n, l)
  74. y.AssertTruef(int(n) <= len(s.buf),
  75. "Arena too small, toWrite:%d newTotal:%d limit:%d",
  76. l, n, len(s.buf))
  77. m := n - l
  78. v.Encode(s.buf[m:])
  79. return m
  80. }
  81. func (s *Arena) putKey(key []byte) uint32 {
  82. l := uint32(len(key))
  83. n := atomic.AddUint32(&s.n, l)
  84. y.AssertTruef(int(n) <= len(s.buf),
  85. "Arena too small, toWrite:%d newTotal:%d limit:%d",
  86. l, n, len(s.buf))
  87. m := n - l
  88. y.AssertTrue(len(key) == copy(s.buf[m:n], key))
  89. return m
  90. }
  91. // getNode returns a pointer to the node located at offset. If the offset is
  92. // zero, then the nil node pointer is returned.
  93. func (s *Arena) getNode(offset uint32) *node {
  94. if offset == 0 {
  95. return nil
  96. }
  97. return (*node)(unsafe.Pointer(&s.buf[offset]))
  98. }
  99. // getKey returns byte slice at offset.
  100. func (s *Arena) getKey(offset uint32, size uint16) []byte {
  101. return s.buf[offset : offset+uint32(size)]
  102. }
  103. // getVal returns byte slice at offset. The given size should be just the value
  104. // size and should NOT include the meta bytes.
  105. func (s *Arena) getVal(offset uint32, size uint16) (ret y.ValueStruct) {
  106. ret.Decode(s.buf[offset : offset+uint32(size)])
  107. return
  108. }
  109. // getNodeOffset returns the offset of node in the arena. If the node pointer is
  110. // nil, then the zero offset is returned.
  111. func (s *Arena) getNodeOffset(nd *node) uint32 {
  112. if nd == nil {
  113. return 0
  114. }
  115. return uint32(uintptr(unsafe.Pointer(nd)) - uintptr(unsafe.Pointer(&s.buf[0])))
  116. }