123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241 |
- /*
- * EliasDB
- *
- * Copyright 2016 Matthias Ladkau. All rights reserved.
- *
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this
- * file, You can obtain one at http://mozilla.org/MPL/2.0/.
- */
- /*
- Package slotting contains managers which deal with slots on pages.
- FreeLogicalSlotManager
- FreeLogicalSlotManager is a list manager for free logical slots. This manager
- object is used by the LogicalSlotManager.
- FreePhysicalSlotManager
- FreePhysicalSlotManager is a list manager for free physical slots. This manager
- object is used by the PhysicalSlotManager.
- LogicalSlotManager
- LogicalSlotManager is a list manager for logical slots. Logical slots are stored
- on translation pages which store just pointers to physical slots.
- PhysicalSlotManager
- PhysicalSlotManager is a list manager for physical slots.
- */
- package slotting
- import (
- "fmt"
- "devt.de/krotik/eliasdb/storage/file"
- "devt.de/krotik/eliasdb/storage/paging"
- "devt.de/krotik/eliasdb/storage/paging/view"
- "devt.de/krotik/eliasdb/storage/slotting/pageview"
- "devt.de/krotik/eliasdb/storage/util"
- )
- /*
- FreeLogicalSlotManager data structure
- */
- type FreeLogicalSlotManager struct {
- storagefile *file.StorageFile // StorageFile which is wrapped
- pager *paging.PagedStorageFile // Pager for StorageFile
- slots []uint64 // List of free slots
- }
- /*
- NewFreeLogicalSlotManager creates a new object to manage free logical slots.
- */
- func NewFreeLogicalSlotManager(psf *paging.PagedStorageFile) *FreeLogicalSlotManager {
- return &FreeLogicalSlotManager{psf.StorageFile(), psf, make([]uint64, 0)}
- }
- /*
- Get gets a free slot.
- */
- func (flsm *FreeLogicalSlotManager) Get() (uint64, error) {
- // Try to get entry from the slots list
- if len(flsm.slots) > 0 {
- freeSlot := flsm.slots[len(flsm.slots)-1]
- flsm.slots = flsm.slots[:len(flsm.slots)-1]
- return freeSlot, nil
- }
- cursor := paging.NewPageCursor(flsm.pager, view.TypeFreeLogicalSlotPage, 0)
- // No need for error checking on cursor next since all pages will be opened
- // via Get calls in the loop.
- page, _ := cursor.Next()
- for page != 0 {
- record, err := flsm.storagefile.Get(page)
- if err != nil {
- return 0, err
- }
- flsp := pageview.NewFreeLogicalSlotPage(record)
- slot := flsp.FirstAllocatedSlotInfo()
- if slot != -1 {
- // Return a found slot and free the free page if necessary
- loc := flsp.SlotInfoLocation(uint16(slot))
- // Release the slot
- flsp.ReleaseSlotInfo(uint16(slot))
- if flsp.FreeSlotCount() == 0 {
- // Free the page if no free row id slot is left
- flsm.storagefile.ReleaseInUseID(page, false)
- flsm.pager.FreePage(page)
- } else {
- flsm.storagefile.ReleaseInUseID(page, true)
- }
- return loc, nil
- }
- flsm.storagefile.ReleaseInUseID(page, false)
- page, _ = cursor.Next()
- }
- return 0, nil
- }
- /*
- Add adds a slot to the free slot set.
- */
- func (flsm *FreeLogicalSlotManager) Add(loc uint64) {
- if loc == 0 {
- // The bit pattern for the 0 location is used to mark free slots
- panic("Illigal free logical slot pattern: 0x0")
- }
- flsm.slots = append(flsm.slots, loc)
- }
- /*
- Flush writes all added slotinfos to FreeLogicalSlotPages.
- */
- func (flsm *FreeLogicalSlotManager) Flush() error {
- cursor := paging.NewPageCursor(flsm.pager, view.TypeFreeLogicalSlotPage, 0)
- index := 0
- // Go through all free logical slot pages
- // No need for error checking on cursor next since all pages will be opened
- // via Get calls in the loop.
- page, _ := cursor.Next()
- for page != 0 {
- // Need to declare err here otherwise index becomes a local for
- // the "for" block
- var err error
- index, err = flsm.doFlush(page, index)
- if err != nil {
- return err
- }
- if index >= len(flsm.slots) {
- break
- }
- page, _ = cursor.Next()
- }
- // Allocate new free logical slot pages if all present ones are full
- // and we have still slots to process
- for index < len(flsm.slots) {
- allocPage, err := flsm.pager.AllocatePage(view.TypeFreeLogicalSlotPage)
- if err != nil {
- return err
- }
- index, err = flsm.doFlush(allocPage, index)
- if err != nil {
- // Try to free the allocated page if there was an error
- // ignore any error of the FreePage call
- flsm.pager.FreePage(allocPage)
- return err
- }
- }
- // Clear lists after all slots information have been written
- flsm.slots = make([]uint64, 0)
- return nil
- }
- /*
- doFlush writes all added slotinfos to a FreeLogicalSlotPage. Stop if the page is full.
- */
- func (flsm *FreeLogicalSlotManager) doFlush(page uint64, index int) (int, error) {
- r, err := flsm.storagefile.Get(page)
- if err != nil {
- return index, err
- }
- flsp := pageview.NewFreeLogicalSlotPage(r)
- // Iterate all page slots (stop if the page has no more available slots
- // or we reached the end of the page)
- slot := flsp.FirstFreeSlotInfo()
- for ; slot != -1 && index < len(flsm.slots); index++ {
- loc := flsm.slots[index]
- offset := flsp.AllocateSlotInfo(uint16(slot))
- flsp.SetSlotInfo(offset, util.LocationRecord(loc), util.LocationOffset(loc))
- slot = flsp.FirstFreeSlotInfo()
- }
- flsm.storagefile.ReleaseInUseID(page, true)
- return index, nil
- }
- /*
- Returns a string representation of this FreeLogicalSlotManager.
- */
- func (flsm *FreeLogicalSlotManager) String() string {
- return fmt.Sprintf("FreeLogicalSlotManager: %v\nIds :%v\n",
- flsm.storagefile.Name(), flsm.slots)
- }
|