freelogicalslotmanager.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241
  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. /*
  11. Package slotting contains managers which deal with slots on pages.
  12. FreeLogicalSlotManager
  13. FreeLogicalSlotManager is a list manager for free logical slots. This manager
  14. object is used by the LogicalSlotManager.
  15. FreePhysicalSlotManager
  16. FreePhysicalSlotManager is a list manager for free physical slots. This manager
  17. object is used by the PhysicalSlotManager.
  18. LogicalSlotManager
  19. LogicalSlotManager is a list manager for logical slots. Logical slots are stored
  20. on translation pages which store just pointers to physical slots.
  21. PhysicalSlotManager
  22. PhysicalSlotManager is a list manager for physical slots.
  23. */
  24. package slotting
  25. import (
  26. "fmt"
  27. "devt.de/krotik/eliasdb/storage/file"
  28. "devt.de/krotik/eliasdb/storage/paging"
  29. "devt.de/krotik/eliasdb/storage/paging/view"
  30. "devt.de/krotik/eliasdb/storage/slotting/pageview"
  31. "devt.de/krotik/eliasdb/storage/util"
  32. )
  33. /*
  34. FreeLogicalSlotManager data structure
  35. */
  36. type FreeLogicalSlotManager struct {
  37. storagefile *file.StorageFile // StorageFile which is wrapped
  38. pager *paging.PagedStorageFile // Pager for StorageFile
  39. slots []uint64 // List of free slots
  40. }
  41. /*
  42. NewFreeLogicalSlotManager creates a new object to manage free logical slots.
  43. */
  44. func NewFreeLogicalSlotManager(psf *paging.PagedStorageFile) *FreeLogicalSlotManager {
  45. return &FreeLogicalSlotManager{psf.StorageFile(), psf, make([]uint64, 0)}
  46. }
  47. /*
  48. Get gets a free slot.
  49. */
  50. func (flsm *FreeLogicalSlotManager) Get() (uint64, error) {
  51. // Try to get entry from the slots list
  52. if len(flsm.slots) > 0 {
  53. freeSlot := flsm.slots[len(flsm.slots)-1]
  54. flsm.slots = flsm.slots[:len(flsm.slots)-1]
  55. return freeSlot, nil
  56. }
  57. cursor := paging.NewPageCursor(flsm.pager, view.TypeFreeLogicalSlotPage, 0)
  58. // No need for error checking on cursor next since all pages will be opened
  59. // via Get calls in the loop.
  60. page, _ := cursor.Next()
  61. for page != 0 {
  62. record, err := flsm.storagefile.Get(page)
  63. if err != nil {
  64. return 0, err
  65. }
  66. flsp := pageview.NewFreeLogicalSlotPage(record)
  67. slot := flsp.FirstAllocatedSlotInfo()
  68. if slot != -1 {
  69. // Return a found slot and free the free page if necessary
  70. loc := flsp.SlotInfoLocation(uint16(slot))
  71. // Release the slot
  72. flsp.ReleaseSlotInfo(uint16(slot))
  73. if flsp.FreeSlotCount() == 0 {
  74. // Free the page if no free row id slot is left
  75. flsm.storagefile.ReleaseInUseID(page, false)
  76. flsm.pager.FreePage(page)
  77. } else {
  78. flsm.storagefile.ReleaseInUseID(page, true)
  79. }
  80. return loc, nil
  81. }
  82. flsm.storagefile.ReleaseInUseID(page, false)
  83. page, _ = cursor.Next()
  84. }
  85. return 0, nil
  86. }
  87. /*
  88. Add adds a slot to the free slot set.
  89. */
  90. func (flsm *FreeLogicalSlotManager) Add(loc uint64) {
  91. if loc == 0 {
  92. // The bit pattern for the 0 location is used to mark free slots
  93. panic("Illigal free logical slot pattern: 0x0")
  94. }
  95. flsm.slots = append(flsm.slots, loc)
  96. }
  97. /*
  98. Flush writes all added slotinfos to FreeLogicalSlotPages.
  99. */
  100. func (flsm *FreeLogicalSlotManager) Flush() error {
  101. cursor := paging.NewPageCursor(flsm.pager, view.TypeFreeLogicalSlotPage, 0)
  102. index := 0
  103. // Go through all free logical slot pages
  104. // No need for error checking on cursor next since all pages will be opened
  105. // via Get calls in the loop.
  106. page, _ := cursor.Next()
  107. for page != 0 {
  108. // Need to declare err here otherwise index becomes a local for
  109. // the "for" block
  110. var err error
  111. index, err = flsm.doFlush(page, index)
  112. if err != nil {
  113. return err
  114. }
  115. if index >= len(flsm.slots) {
  116. break
  117. }
  118. page, _ = cursor.Next()
  119. }
  120. // Allocate new free logical slot pages if all present ones are full
  121. // and we have still slots to process
  122. for index < len(flsm.slots) {
  123. allocPage, err := flsm.pager.AllocatePage(view.TypeFreeLogicalSlotPage)
  124. if err != nil {
  125. return err
  126. }
  127. index, err = flsm.doFlush(allocPage, index)
  128. if err != nil {
  129. // Try to free the allocated page if there was an error
  130. // ignore any error of the FreePage call
  131. flsm.pager.FreePage(allocPage)
  132. return err
  133. }
  134. }
  135. // Clear lists after all slots information have been written
  136. flsm.slots = make([]uint64, 0)
  137. return nil
  138. }
  139. /*
  140. doFlush writes all added slotinfos to a FreeLogicalSlotPage. Stop if the page is full.
  141. */
  142. func (flsm *FreeLogicalSlotManager) doFlush(page uint64, index int) (int, error) {
  143. r, err := flsm.storagefile.Get(page)
  144. if err != nil {
  145. return index, err
  146. }
  147. flsp := pageview.NewFreeLogicalSlotPage(r)
  148. // Iterate all page slots (stop if the page has no more available slots
  149. // or we reached the end of the page)
  150. slot := flsp.FirstFreeSlotInfo()
  151. for ; slot != -1 && index < len(flsm.slots); index++ {
  152. loc := flsm.slots[index]
  153. offset := flsp.AllocateSlotInfo(uint16(slot))
  154. flsp.SetSlotInfo(offset, util.LocationRecord(loc), util.LocationOffset(loc))
  155. slot = flsp.FirstFreeSlotInfo()
  156. }
  157. flsm.storagefile.ReleaseInUseID(page, true)
  158. return index, nil
  159. }
  160. /*
  161. Returns a string representation of this FreeLogicalSlotManager.
  162. */
  163. func (flsm *FreeLogicalSlotManager) String() string {
  164. return fmt.Sprintf("FreeLogicalSlotManager: %v\nIds :%v\n",
  165. flsm.storagefile.Name(), flsm.slots)
  166. }