freelogicalslotpage.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165
  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 pageview
  11. import (
  12. "devt.de/krotik/eliasdb/storage/file"
  13. "devt.de/krotik/eliasdb/storage/paging/view"
  14. "devt.de/krotik/eliasdb/storage/util"
  15. )
  16. // OFFSET_COUNT / OFFSET_DATA declared in freephysicalslotpage
  17. /*
  18. FreeLogicalSlotPage data structure
  19. */
  20. type FreeLogicalSlotPage struct {
  21. *SlotInfoPage
  22. maxSlots uint16 // Max number of slots
  23. prevFoundFreeSlot uint16 // Previous found free slot
  24. prevFoundAllocatedSlot uint16 // Previous allocated slot
  25. }
  26. /*
  27. NewFreeLogicalSlotPage creates a new page which can manage free slots.
  28. */
  29. func NewFreeLogicalSlotPage(record *file.Record) *FreeLogicalSlotPage {
  30. checkFreeLogicalSlotPageMagic(record)
  31. maxSlots := (len(record.Data()) - OffsetData) / util.LocationSize
  32. return &FreeLogicalSlotPage{NewSlotInfoPage(record), uint16(maxSlots), 0, 0}
  33. }
  34. /*
  35. checkFreeLogicalSlotPageMagic checks if the magic number at the beginning of
  36. the wrapped record is valid.
  37. */
  38. func checkFreeLogicalSlotPageMagic(record *file.Record) bool {
  39. magic := record.ReadInt16(0)
  40. if magic == view.ViewPageHeader+view.TypeFreeLogicalSlotPage {
  41. return true
  42. }
  43. panic("Unexpected header found in FreeLogicalSlotPage")
  44. }
  45. /*
  46. MaxSlots returns the maximum number of slots which can be allocated.
  47. */
  48. func (flsp *FreeLogicalSlotPage) MaxSlots() uint16 {
  49. return flsp.maxSlots
  50. }
  51. /*
  52. FreeSlotCount returns the number of free slots on this page.
  53. */
  54. func (flsp *FreeLogicalSlotPage) FreeSlotCount() uint16 {
  55. return flsp.Record.ReadUInt16(OffsetCount)
  56. }
  57. /*
  58. SlotInfoLocation returns contents of a stored slotinfo as a location. Lookup is via a
  59. given slotinfo id.
  60. */
  61. func (flsp *FreeLogicalSlotPage) SlotInfoLocation(slotinfo uint16) uint64 {
  62. offset := flsp.slotinfoToOffset(slotinfo)
  63. return util.PackLocation(flsp.SlotInfoRecord(offset), flsp.SlotInfoOffset(offset))
  64. }
  65. /*
  66. AllocateSlotInfo allocates a place for a slotinfo and returns the offset for it.
  67. */
  68. func (flsp *FreeLogicalSlotPage) AllocateSlotInfo(slotinfo uint16) uint16 {
  69. offset := flsp.slotinfoToOffset(slotinfo)
  70. // Set slotinfo to initial values
  71. flsp.SetSlotInfo(offset, 1, 1)
  72. // Increase counter for allocated slotinfos
  73. flsp.Record.WriteUInt16(OffsetCount, flsp.FreeSlotCount()+1)
  74. // Update prevFoundAllocatedSlot if necessary
  75. if slotinfo < flsp.prevFoundAllocatedSlot {
  76. flsp.prevFoundAllocatedSlot = slotinfo
  77. }
  78. return offset
  79. }
  80. /*
  81. ReleaseSlotInfo releases a place for a slotinfo and return its offset.
  82. */
  83. func (flsp *FreeLogicalSlotPage) ReleaseSlotInfo(slotinfo uint16) uint16 {
  84. offset := flsp.slotinfoToOffset(slotinfo)
  85. // Set slotinfo to empty values
  86. flsp.SetSlotInfo(offset, 0, 0)
  87. // Decrease counter for allocated slotinfos
  88. flsp.Record.WriteUInt16(OffsetCount, flsp.FreeSlotCount()-1)
  89. // Update prevFoundFreeSlot if necessary
  90. if slotinfo < flsp.prevFoundFreeSlot {
  91. flsp.prevFoundFreeSlot = slotinfo
  92. }
  93. return offset
  94. }
  95. /*
  96. FirstFreeSlotInfo returns the id for the first available slotinfo or -1 if
  97. nothing is available.
  98. */
  99. func (flsp *FreeLogicalSlotPage) FirstFreeSlotInfo() int {
  100. for flsp.prevFoundFreeSlot < flsp.maxSlots {
  101. if !flsp.isAllocatedSlot(flsp.prevFoundFreeSlot) {
  102. return int(flsp.prevFoundFreeSlot)
  103. }
  104. flsp.prevFoundFreeSlot++
  105. }
  106. return -1
  107. }
  108. /*
  109. FirstAllocatedSlotInfo returns the id for the first allocated slotinfo or -1 if
  110. nothing is allocated.
  111. */
  112. func (flsp *FreeLogicalSlotPage) FirstAllocatedSlotInfo() int {
  113. for flsp.prevFoundAllocatedSlot < flsp.maxSlots {
  114. if flsp.isAllocatedSlot(flsp.prevFoundAllocatedSlot) {
  115. return int(flsp.prevFoundAllocatedSlot)
  116. }
  117. flsp.prevFoundAllocatedSlot++
  118. }
  119. return -1
  120. }
  121. /*
  122. isAllocatedSlot checks if a given slotinfo is allocated.
  123. */
  124. func (flsp *FreeLogicalSlotPage) isAllocatedSlot(slotinfo uint16) bool {
  125. offset := flsp.slotinfoToOffset(slotinfo)
  126. return flsp.SlotInfoRecord(offset) != 0 || flsp.SlotInfoOffset(offset) != 0
  127. }
  128. /*
  129. slotinfoToOffset converts a slotinfo number into an offset on the record.
  130. */
  131. func (flsp *FreeLogicalSlotPage) slotinfoToOffset(slotinfo uint16) uint16 {
  132. return OffsetData + slotinfo*util.LocationSize
  133. }