htreepage.go 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393
  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 hash
  11. import (
  12. "bytes"
  13. "fmt"
  14. )
  15. /*
  16. htreePage data structure
  17. */
  18. type htreePage struct {
  19. *htreeNode
  20. }
  21. /*
  22. newHTreePage creates a new page for the HTree.
  23. */
  24. func newHTreePage(tree *HTree, depth byte) *htreePage {
  25. return &htreePage{&htreeNode{tree, 0, nil, depth, make([]uint64, MaxPageChildren), nil, nil, 0}}
  26. }
  27. /*
  28. IsEmpty returns if this page is empty.
  29. */
  30. func (p *htreePage) IsEmpty() bool {
  31. for _, child := range p.Children {
  32. if child != 0 {
  33. return false
  34. }
  35. }
  36. return true
  37. }
  38. /*
  39. Location returns the location of this HTree page.
  40. */
  41. func (p *htreePage) Location() uint64 {
  42. return p.loc
  43. }
  44. /*
  45. Get gets a value for a given key.
  46. */
  47. func (p *htreePage) Get(key []byte) (interface{}, *htreeBucket, error) {
  48. hash := p.hashKey(key)
  49. loc := p.Children[hash]
  50. if loc != 0 {
  51. node, err := p.fetchNode(loc)
  52. if err != nil {
  53. return nil, nil, err
  54. }
  55. if node.Children != nil {
  56. // If another page was found deligate the request
  57. page := &htreePage{node}
  58. page.loc = loc
  59. page.sm = p.sm
  60. return page.Get(key)
  61. }
  62. // If a Bucket was found return the value
  63. bucket := &htreeBucket{node}
  64. bucket.loc = loc
  65. bucket.sm = p.sm
  66. return bucket.Get(key), bucket, nil
  67. }
  68. return nil, nil, nil
  69. }
  70. /*
  71. Exists checks if an element exists.
  72. */
  73. func (p *htreePage) Exists(key []byte) (bool, error) {
  74. hash := p.hashKey(key)
  75. loc := p.Children[hash]
  76. if loc != 0 {
  77. node, err := p.fetchNode(loc)
  78. if err != nil {
  79. return false, err
  80. }
  81. if node.Children != nil {
  82. // If another page was found deligate the request
  83. page := &htreePage{node}
  84. page.loc = loc
  85. page.sm = p.sm
  86. return page.Exists(key)
  87. }
  88. // If a Bucket was found return the value
  89. bucket := &htreeBucket{node}
  90. return bucket.Exists(key), nil
  91. }
  92. return false, nil
  93. }
  94. /*
  95. Put adds or updates a new key / value pair.
  96. */
  97. func (p *htreePage) Put(key []byte, value interface{}) (interface{}, error) {
  98. // Putting a nil values will remove the element
  99. if value == nil {
  100. return p.Remove(key)
  101. }
  102. hash := p.hashKey(key)
  103. loc := p.Children[hash]
  104. if loc == 0 {
  105. // If nothing exists yet for the hash code then create a new bucket
  106. bucket := newHTreeBucket(p.tree, p.Depth+1)
  107. existing := bucket.Put(key, value)
  108. loc, err := p.sm.Insert(bucket.htreeNode)
  109. if err != nil {
  110. return nil, err
  111. }
  112. bucket.loc = loc
  113. bucket.sm = p.sm
  114. p.Children[hash] = loc
  115. err = p.sm.Update(p.loc, p.htreeNode)
  116. if err != nil {
  117. return nil, err
  118. }
  119. return existing, nil
  120. }
  121. // If a bucket was found try to put the value on it if there is room
  122. node, err := p.fetchNode(loc)
  123. if err != nil {
  124. return false, err
  125. }
  126. if node.Children != nil {
  127. // If another page was found deligate the request
  128. page := &htreePage{node}
  129. page.loc = loc
  130. page.sm = p.sm
  131. return page.Put(key, value)
  132. }
  133. // If a bucket was found try to put the value on it if there is room
  134. bucket := &htreeBucket{node}
  135. bucket.loc = loc
  136. bucket.sm = p.sm
  137. if bucket.HasRoom() {
  138. existing := bucket.Put(key, value)
  139. return existing, p.sm.Update(bucket.loc, bucket.htreeNode)
  140. }
  141. // If the bucket is too full create a new directory
  142. if p.Depth == MaxTreeDepth {
  143. panic("Max depth of HTree exceeded")
  144. }
  145. page := newHTreePage(p.tree, p.Depth+1)
  146. ploc, err := p.sm.Insert(page.htreeNode)
  147. if err != nil {
  148. return nil, err
  149. }
  150. page.loc = ploc
  151. page.sm = p.sm
  152. p.Children[hash] = ploc
  153. if err := p.sm.Update(p.loc, p.htreeNode); err != nil {
  154. // Try to clean up
  155. p.Children[hash] = loc
  156. p.sm.Free(ploc)
  157. return nil, err
  158. }
  159. // At this point the bucket has been removed from the list of children
  160. // It is no longer part of the tree
  161. // Try inserting all keys of the bucket into the newly created page
  162. // and remove the bucket - no error checking here - the recovery
  163. // steps are too eloborate with little chance of success they
  164. // might also damage the now intact tree
  165. for i, key := range bucket.Keys {
  166. page.Put(key, bucket.Values[i])
  167. }
  168. // Remove old bucket from file
  169. p.sm.Free(bucket.loc)
  170. // Finally insert key / value pair
  171. return page.Put(key, value)
  172. }
  173. /*
  174. Remove removes a key / value pair.
  175. */
  176. func (p *htreePage) Remove(key []byte) (interface{}, error) {
  177. hash := p.hashKey(key)
  178. loc := p.Children[hash]
  179. // Return if there is nothing to delete
  180. if loc == 0 {
  181. return nil, nil
  182. }
  183. node, err := p.fetchNode(loc)
  184. if err != nil {
  185. return false, err
  186. }
  187. if node.Children != nil {
  188. // If another page was found deligate the request
  189. page := &htreePage{node}
  190. page.loc = loc
  191. page.sm = p.sm
  192. ret, err := page.Remove(key)
  193. if err != nil {
  194. return ret, err
  195. }
  196. if page.IsEmpty() {
  197. // Remove page if it is empty
  198. p.Children[hash] = 0
  199. if err := p.sm.Update(p.loc, p.htreeNode); err != nil {
  200. return nil, err
  201. }
  202. return ret, p.sm.Free(loc)
  203. }
  204. return ret, nil
  205. }
  206. // If a bucket is found just remove the key / value pair
  207. bucket := &htreeBucket{node}
  208. bucket.loc = loc
  209. bucket.sm = p.sm
  210. ret := bucket.Remove(key)
  211. // Either update or remove the bucket
  212. if bucket.Size() > 0 {
  213. return ret, p.sm.Update(bucket.loc, bucket.htreeNode)
  214. }
  215. p.Children[hash] = 0
  216. if err := p.sm.Update(p.loc, p.htreeNode); err != nil {
  217. return nil, err
  218. }
  219. return ret, p.sm.Free(loc)
  220. }
  221. /*
  222. String returns a string representation of this page.
  223. */
  224. func (p *htreePage) String() string {
  225. var j byte
  226. buf := new(bytes.Buffer)
  227. for j = 0; j < p.Depth; j++ {
  228. buf.WriteString(" ")
  229. }
  230. buf.WriteString(fmt.Sprintf("HashPage %v (depth: %v)\n", p.loc, p.Depth))
  231. for hash, child := range p.Children {
  232. if child != 0 {
  233. for j = 0; j < p.Depth+1; j++ {
  234. buf.WriteString(" ")
  235. }
  236. buf.WriteString(fmt.Sprintf("Hash %08X (loc: %v)\n", hash, child))
  237. node, err := p.fetchNode(child)
  238. if err != nil {
  239. buf.WriteString(err.Error())
  240. buf.WriteString("\n")
  241. } else if node.Children != nil {
  242. page := &htreePage{node}
  243. page.loc = child
  244. page.sm = p.sm
  245. buf.WriteString(page.String())
  246. } else {
  247. bucket := &htreeBucket{node}
  248. buf.WriteString(bucket.String())
  249. }
  250. }
  251. }
  252. return buf.String()
  253. }
  254. /*
  255. hashKey calculates the hash code for a given key.
  256. */
  257. func (p *htreePage) hashKey(key []byte) uint32 {
  258. var hash, hashMask uint32
  259. // Calculate mask depending on page depth
  260. // 0 masks out most significant bits while 2 masks out least significant bits
  261. hashMask = (MaxPageChildren - 1) << ((MaxTreeDepth - p.Depth) * PageLevelBits)
  262. // Calculate hash and apply mask
  263. hash, _ = MurMurHashData(key, 0, len(key)-1, 42)
  264. hash = hash & hashMask
  265. // Move the bytes to the least significant position
  266. hash = hash >> ((MaxTreeDepth - p.Depth) * PageLevelBits)
  267. return hash % MaxPageChildren
  268. }