/* * 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 import ( "testing" "devt.de/krotik/eliasdb/storage/file" "devt.de/krotik/eliasdb/storage/paging" "devt.de/krotik/eliasdb/storage/slotting/pageview" "devt.de/krotik/eliasdb/storage/util" ) func TestLogicalSlotManager(t *testing.T) { sf, err := file.NewDefaultStorageFile(DBDIR+"/test8_data", false) if err != nil { t.Error(err.Error()) return } psf, err := paging.NewPagedStorageFile(sf) if err != nil { t.Error(err) return } fsf, err := file.NewDefaultStorageFile(DBDIR+"/test8_free", false) if err != nil { t.Error(err.Error()) return } fpsf, err := paging.NewPagedStorageFile(fsf) if err != nil { t.Error(err) return } lsm := NewLogicalSlotManager(psf, fpsf) if lsm.ElementsPerPage() != 509 { t.Error("Unexpected elements per page:", lsm.ElementsPerPage()) return } // Check return value when fetching from a logical slot which doesn't yet exist slotinfo, err := lsm.Fetch(util.PackLocation(1, pageview.OffsetTransData)) if slotinfo != 0 || err != nil { t.Error("Unexpected fetch result:", slotinfo, err) } // Test insertion error record, err := sf.Get(1) if err != nil { t.Error(err) return } _, err = lsm.Insert(util.PackLocation(10, 11)) if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse { t.Error(err) return } sf.ReleaseInUse(record) // Test insertion error when allocating free slots record, err = fsf.Get(1) if err != nil { t.Error(err) return } _, err = lsm.Insert(util.PackLocation(10, 11)) if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse { t.Error(err) return } fsf.ReleaseInUse(record) // Insert a locations loc, err := lsm.Insert(util.PackLocation(10, 11)) if err != nil { t.Error(err) return } checkLocation(t, loc, 1, pageview.OffsetTransData) // Test error checking when force inserting a location (page does not exist) record, err = sf.Get(2) if err != nil { t.Error(err) return } err = lsm.ForceInsert(util.PackLocation(2, 2), util.PackLocation(12, 13)) if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse { t.Error(err) return } sf.ReleaseInUse(record) // Force insert a location if err = lsm.ForceInsert(util.PackLocation(2, 2), util.PackLocation(12, 13)); err != nil { t.Error(err) return } // Test error checking when force inserting a location (this time the page exists) record, err = sf.Get(2) if err != nil { t.Error(err) return } err = lsm.ForceInsert(util.PackLocation(2, 2), util.PackLocation(12, 13)) if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse { t.Error(err) return } sf.ReleaseInUse(record) testForceInsertPanic(t, lsm) // Check that the physical slot infos have been stored in the logical slots _testLogicalSlot(t, sf, 1, pageview.OffsetTransData, 10, 11) _testLogicalSlot(t, sf, 2, 2, 12, 13) // Free a slot record, err = sf.Get(2) if err != nil { t.Error(err) return } err = lsm.Free(util.PackLocation(2, 2)) if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse { t.Error("Unexpected free result:", err) return } sf.ReleaseInUse(record) if err = lsm.Free(util.PackLocation(2, 2)); err != nil { t.Error(err) return } // Check error when fetching from the free manager (the free manager has // nothing stored but should fail since it can't look on page 1) record, err = fsf.Get(1) if err != nil { t.Error(err) return } _, err = lsm.Insert(util.PackLocation(12, 13)) if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse { t.Error("Unexpected free result:", err) return } fsf.ReleaseInUse(record) // Check error when updating a logical slot record, err = sf.Get(1) if err != nil { t.Error(err) return } err = lsm.Update(util.PackLocation(1, 3), util.PackLocation(12, 13)) if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse { t.Error("Unexpected update result:", err) return } sf.ReleaseInUse(record) if err := psf.Close(); err != nil { t.Error(err) return } if err := fpsf.Close(); err != nil { t.Error(err) return } } func testForceInsertPanic(t *testing.T, lsm *LogicalSlotManager) { defer func() { if r := recover(); r == nil { t.Error("Force inserting to an existing location did not cause a panic.") } }() lsm.ForceInsert(util.PackLocation(2, 2), util.PackLocation(12, 13)) } func _testLogicalSlot(t *testing.T, sf *file.StorageFile, logicalRecord uint64, logicalOffset uint16, physicalRecord uint64, physicalOffset uint16) { record, err := sf.Get(logicalRecord) if err != nil { t.Error(err) return } slotinfo := record.ReadUInt64(int(logicalOffset)) if slotinfo != util.PackLocation(physicalRecord, physicalOffset) { t.Error("Unexpected physical location was stored in logical slot:", logicalRecord, logicalOffset, " expected:", physicalRecord, physicalOffset, "got:", util.LocationRecord(slotinfo), util.LocationOffset(slotinfo)) } sf.ReleaseInUse(record) }