slotsize.go 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193
  1. /*
  2. * EliasDB
  3. *
  4. * Copyright 2016 Matthias Ladkau. All rights reserved.
  5. *
  6. * This Source Code Form is subject to the terms of the Mozilla Public
  7. * License, v. 2.0. If a copy of the MPL was not distributed with this
  8. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
  9. */
  10. package util
  11. import (
  12. "fmt"
  13. "devt.de/krotik/eliasdb/storage/file"
  14. )
  15. /*
  16. OffsetCurrentSize is the offset for the size on a slotsize header.
  17. */
  18. const OffsetCurrentSize = 0
  19. /*
  20. OffetAvailableSize is the offset for the available size on a slotsize header.
  21. */
  22. const OffetAvailableSize = file.SizeUnsignedShort
  23. /*
  24. UnsignedShortMax is the maximum value of an unsigned short as used for slotsizes.
  25. */
  26. const UnsignedShortMax = 0xFFFF
  27. /*
  28. MaxAvailableSizeDifference represents the maximal size of the difference
  29. between available size and current size
  30. */
  31. const MaxAvailableSizeDifference = UnsignedShortMax - 1
  32. /*
  33. SizeInfoSize represents the size of the size info
  34. */
  35. const SizeInfoSize = OffetAvailableSize + file.SizeUnsignedShort
  36. /*
  37. CurrentSize returns the current size of a slot.
  38. */
  39. func CurrentSize(record *file.Record, offset int) uint32 {
  40. currentSize := record.ReadUInt16(offset + OffsetCurrentSize)
  41. if currentSize == UnsignedShortMax {
  42. return 0
  43. }
  44. return AvailableSize(record, offset) - uint32(currentSize)
  45. }
  46. /*
  47. SetCurrentSize sets the current size of a slot.
  48. */
  49. func SetCurrentSize(record *file.Record, offset int, value uint32) {
  50. if value == 0 {
  51. record.WriteUInt16(offset+OffsetCurrentSize, UnsignedShortMax)
  52. return
  53. }
  54. size := AvailableSize(record, offset)
  55. if (size > MaxAvailableSizeDifference &&
  56. value < size-MaxAvailableSizeDifference) ||
  57. value > size {
  58. panic(fmt.Sprint("Cannot store current size as difference "+
  59. "to available size. Value:", value, " Available size:", size))
  60. }
  61. record.WriteUInt16(offset+OffsetCurrentSize, uint16(size-value))
  62. }
  63. /*
  64. AvailableSize returns the available size of a slot.
  65. */
  66. func AvailableSize(record *file.Record, offset int) uint32 {
  67. value := record.ReadUInt16(offset + OffetAvailableSize)
  68. return decodeSize(value)
  69. }
  70. /*
  71. SetAvailableSize sets the available size of a slot.
  72. */
  73. func SetAvailableSize(record *file.Record, offset int, value uint32) {
  74. currentSize := CurrentSize(record, offset)
  75. size := encodeSize(value)
  76. // Safeguard against not using normalized size values
  77. if decodeSize(size) != value {
  78. panic("Size value was not normalized")
  79. }
  80. record.WriteUInt16(offset+OffetAvailableSize, size)
  81. // Current size needs to be updated since it depends on the available size
  82. SetCurrentSize(record, offset, currentSize)
  83. }
  84. /*
  85. NormalizeSlotSize normalizes a given slot size.
  86. */
  87. func NormalizeSlotSize(value uint32) uint32 {
  88. return decodeSize(encodeSize(value))
  89. }
  90. const sizeMask = 1<<15 | 1<<14
  91. const multi0 = 1
  92. const multi1 = 1 << 4
  93. const multi2 = 1 << 8
  94. const multi3 = 1 << 13
  95. const base0 = 0
  96. const base1 = base0 + multi0*((1<<14)-2)
  97. const base2 = base1 + multi1*((1<<14)-2)
  98. const base3 = base2 + multi2*((1<<14)-2)
  99. /*
  100. decodeSize decodes a given size value.
  101. */
  102. func decodeSize(packedSize uint16) uint32 {
  103. size := packedSize & sizeMask
  104. multiplier := size >> 14
  105. counter := uint32(packedSize - size)
  106. switch multiplier {
  107. case 0:
  108. return counter * multi0
  109. case 1:
  110. return base1 + counter*multi1
  111. case 2:
  112. return base2 + counter*multi2
  113. default:
  114. return base3 + counter*multi3
  115. }
  116. }
  117. /*
  118. encodeSize encodes a given size value.
  119. */
  120. func encodeSize(size uint32) uint16 {
  121. var multiplier, counter, v uint32
  122. switch {
  123. case size <= base1:
  124. multiplier = 0
  125. counter = size / multi0
  126. case size < base2:
  127. multiplier = 1 << 14
  128. v = size - base1
  129. counter = v / multi1
  130. if v%multi1 != 0 {
  131. counter++
  132. }
  133. case size < base3:
  134. multiplier = 2 << 14
  135. v = size - base2
  136. counter = v / multi2
  137. if v%multi2 != 0 {
  138. counter++
  139. }
  140. default:
  141. multiplier = 3 << 14
  142. v = size - base3
  143. counter = v / multi3
  144. if v%multi3 != 0 {
  145. counter++
  146. }
  147. }
  148. if counter >= (1 << 14) {
  149. panic(fmt.Sprint("Cannot pack slot size:", size))
  150. }
  151. return uint16(multiplier + counter)
  152. }