| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165 | /* * 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 pageviewimport (	"devt.de/krotik/eliasdb/storage/file"	"devt.de/krotik/eliasdb/storage/paging/view"	"devt.de/krotik/eliasdb/storage/util")// OFFSET_COUNT / OFFSET_DATA declared in freephysicalslotpage/*FreeLogicalSlotPage data structure*/type FreeLogicalSlotPage struct {	*SlotInfoPage	maxSlots               uint16 // Max number of slots	prevFoundFreeSlot      uint16 // Previous found free slot	prevFoundAllocatedSlot uint16 // Previous allocated slot}/*NewFreeLogicalSlotPage creates a new page which can manage free slots.*/func NewFreeLogicalSlotPage(record *file.Record) *FreeLogicalSlotPage {	checkFreeLogicalSlotPageMagic(record)	maxSlots := (len(record.Data()) - OffsetData) / util.LocationSize	return &FreeLogicalSlotPage{NewSlotInfoPage(record), uint16(maxSlots), 0, 0}}/*checkFreeLogicalSlotPageMagic checks if the magic number at the beginning ofthe wrapped record is valid.*/func checkFreeLogicalSlotPageMagic(record *file.Record) bool {	magic := record.ReadInt16(0)	if magic == view.ViewPageHeader+view.TypeFreeLogicalSlotPage {		return true	}	panic("Unexpected header found in FreeLogicalSlotPage")}/*MaxSlots returns the maximum number of slots which can be allocated.*/func (flsp *FreeLogicalSlotPage) MaxSlots() uint16 {	return flsp.maxSlots}/*FreeSlotCount returns the number of free slots on this page.*/func (flsp *FreeLogicalSlotPage) FreeSlotCount() uint16 {	return flsp.Record.ReadUInt16(OffsetCount)}/*SlotInfoLocation returns contents of a stored slotinfo as a location. Lookup is via agiven slotinfo id.*/func (flsp *FreeLogicalSlotPage) SlotInfoLocation(slotinfo uint16) uint64 {	offset := flsp.slotinfoToOffset(slotinfo)	return util.PackLocation(flsp.SlotInfoRecord(offset), flsp.SlotInfoOffset(offset))}/*AllocateSlotInfo allocates a place for a slotinfo and returns the offset for it.*/func (flsp *FreeLogicalSlotPage) AllocateSlotInfo(slotinfo uint16) uint16 {	offset := flsp.slotinfoToOffset(slotinfo)	// Set slotinfo to initial values	flsp.SetSlotInfo(offset, 1, 1)	// Increase counter for allocated slotinfos	flsp.Record.WriteUInt16(OffsetCount, flsp.FreeSlotCount()+1)	// Update prevFoundAllocatedSlot if necessary	if slotinfo < flsp.prevFoundAllocatedSlot {		flsp.prevFoundAllocatedSlot = slotinfo	}	return offset}/*ReleaseSlotInfo releases a place for a slotinfo and return its offset.*/func (flsp *FreeLogicalSlotPage) ReleaseSlotInfo(slotinfo uint16) uint16 {	offset := flsp.slotinfoToOffset(slotinfo)	// Set slotinfo to empty values	flsp.SetSlotInfo(offset, 0, 0)	// Decrease counter for allocated slotinfos	flsp.Record.WriteUInt16(OffsetCount, flsp.FreeSlotCount()-1)	// Update prevFoundFreeSlot if necessary	if slotinfo < flsp.prevFoundFreeSlot {		flsp.prevFoundFreeSlot = slotinfo	}	return offset}/*FirstFreeSlotInfo returns the id for the first available slotinfo or -1 ifnothing is available.*/func (flsp *FreeLogicalSlotPage) FirstFreeSlotInfo() int {	for flsp.prevFoundFreeSlot < flsp.maxSlots {		if !flsp.isAllocatedSlot(flsp.prevFoundFreeSlot) {			return int(flsp.prevFoundFreeSlot)		}		flsp.prevFoundFreeSlot++	}	return -1}/*FirstAllocatedSlotInfo returns the id for the first allocated slotinfo or -1 ifnothing is allocated.*/func (flsp *FreeLogicalSlotPage) FirstAllocatedSlotInfo() int {	for flsp.prevFoundAllocatedSlot < flsp.maxSlots {		if flsp.isAllocatedSlot(flsp.prevFoundAllocatedSlot) {			return int(flsp.prevFoundAllocatedSlot)		}		flsp.prevFoundAllocatedSlot++	}	return -1}/*isAllocatedSlot checks if a given slotinfo is allocated.*/func (flsp *FreeLogicalSlotPage) isAllocatedSlot(slotinfo uint16) bool {	offset := flsp.slotinfoToOffset(slotinfo)	return flsp.SlotInfoRecord(offset) != 0 || flsp.SlotInfoOffset(offset) != 0}/*slotinfoToOffset converts a slotinfo number into an offset on the record.*/func (flsp *FreeLogicalSlotPage) slotinfoToOffset(slotinfo uint16) uint16 {	return OffsetData + slotinfo*util.LocationSize}
 |