123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403 |
- /*
- * 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 storage
- import (
- "testing"
- "devt.de/krotik/eliasdb/storage/file"
- "devt.de/krotik/eliasdb/storage/slotting/pageview"
- )
- type cachetestobj struct {
- Val1 int
- Val2 string
- }
- func TestCachedDiskStorageManager(t *testing.T) {
- dsm := NewDiskStorageManager(DBDIR+"/ctest1", false, false, true, true)
- if dsm.Name() != "DiskStorageFile:"+DBDIR+"/ctest1" {
- t.Error("Unexpected name for DiskStorageManager:", dsm.Name())
- return
- }
- cdsm := NewCachedDiskStorageManager(dsm, 10)
- // Test the getter and setter fields
- if cdsm.Name() != dsm.Name() {
- t.Error("Unexpected result asking for the name")
- return
- }
- if cdsm.Root(RootIDVersion) != dsm.Root(RootIDVersion) || dsm.Root(RootIDVersion) == 0 {
- t.Error("Unexpected result asking for the version")
- return
- }
- cdsm.SetRoot(5, 20)
- if cdsm.Root(5) != 20 || dsm.Root(5) != 20 {
- t.Error("Unexpected result asking for a root")
- return
- }
- // Test the insert which is not cached
- testObj1 := &cachetestobj{1, "This is a test"}
- testObj2 := &cachetestobj{1, "This is a 7e57"}
- loc, err := cdsm.Insert(testObj1)
- if err != nil {
- t.Error(err)
- return
- }
- // Test getting non-existent entry from cache
- if _, err := cdsm.FetchCached(loc + 1); err.(*ManagerError).Type != ErrNotInCache {
- t.Error("Unexpected FetchCached result:", err)
- return
- }
- // Make sure rollback has no effect if the transactions are disabled
- cdsm.Rollback()
- checkLocation(t, loc, 1, pageview.OffsetTransData)
- if _, ok := cdsm.cache[loc]; !ok {
- t.Error("Cache entry should not be empty")
- return
- }
- var ret1, ret2 cachetestobj
- err = cdsm.Fetch(loc, &ret1)
- if ret1.Val2 != "This is a test" || err != nil {
- t.Error("Unexpected fetch result:", ret1, err)
- return
- }
- // Check cache entry
- if e, ok := cdsm.cache[loc]; !ok || ret1 == e.object ||
- e.object.(*cachetestobj).Val2 != "This is a test" {
- t.Error("Update should store a copy")
- return
- }
- err = dsm.Fetch(loc, &ret2)
- if ret2.Val2 != "This is a test" || err != nil {
- t.Error("Unexpected fetch result:", ret2, err)
- return
- }
- // Test the update which is cached
- if err := cdsm.Update(loc, testObj2); err != nil {
- t.Error(err)
- return
- }
- if testObj2 != cdsm.cache[loc].object {
- t.Error("Cache should contain object which was given by update")
- return
- }
- // Check that we have a cache entry
- err = cdsm.Fetch(loc, &ret2)
- if ret2.Val2 != "This is a 7e57" || err != nil {
- t.Error("Unexpected fetch result:", ret2, err)
- return
- }
- // Test writing a different type
- if err := cdsm.Update(loc, "bla"); err != nil {
- t.Error(err)
- return
- }
- var ret3 string
- err = dsm.Fetch(loc, &ret3)
- if ret3 != "bla" || err != nil {
- t.Error("Unexpected fetch result:", ret3, err)
- return
- }
- // Run update on something which is unknown
- loc, err = cdsm.Insert("test66")
- if err != nil {
- t.Error(err)
- return
- }
- // Here the update should create the cache entry
- err = cdsm.Update(loc, "test77")
- if err != nil {
- t.Error(err)
- return
- }
- var obj interface{}
- obj, _ = cdsm.FetchCached(loc)
- if obj.(string) != "test77" {
- t.Error("Unexpected FetchCached result:", obj)
- return
- }
- err = dsm.Fetch(loc, &ret3)
- if ret3 != "test77" || err != nil {
- t.Error("Unexpected fetch result:", ret3, err)
- return
- }
- loc, err = dsm.Insert("test88")
- if err != nil {
- t.Error(err)
- return
- }
- record, err := dsm.physicalSlotsSf.Get(1)
- if err != nil {
- t.Error(err)
- return
- }
- err = cdsm.Fetch(loc, &ret3)
- if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
- t.Error("Unexpected fetch result:", ret3, err)
- return
- }
- err = cdsm.Update(loc, "test99")
- if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
- t.Error("Unexpected update result:", err)
- return
- }
- if err := cdsm.Flush(); err != nil && err.Error() != "Records are still in-use (storagemanagertest/ctest1.db - Records 1)" {
- t.Error("Unexpected flush result:", err)
- return
- }
- dsm.physicalSlotsSf.ReleaseInUse(record)
- // Flush should now succeed
- if err := cdsm.Flush(); err != nil {
- t.Error(err)
- return
- }
- if err = cdsm.Close(); err != nil {
- t.Error(err)
- }
- }
- func TestCachedDiskStorageManagerTransactions(t *testing.T) {
- dsm := NewDiskStorageManager(DBDIR+"/ctest2", false, false, false, true)
- if dsm.Name() != "DiskStorageFile:"+DBDIR+"/ctest2" {
- t.Error("Unexpected name for DiskStorageManager:", dsm.Name())
- return
- }
- cdsm := NewCachedDiskStorageManager(dsm, 10)
- loc, err := cdsm.Insert("test1")
- if err != nil {
- t.Error(err)
- return
- }
- if err := cdsm.Rollback(); err != nil {
- t.Error(err)
- return
- }
- if _, ok := cdsm.cache[loc]; ok {
- t.Error("Cache entry should be empty")
- return
- }
- var ret string
- if err := cdsm.Fetch(loc, &ret); err.(*ManagerError).Type != ErrSlotNotFound ||
- err.Error() != "Slot not found (ByteDiskStorageFile:storagemanagertest/ctest2 - Location:1 18)" {
- t.Error("Unexpected fetch result:", err)
- return
- }
- // Put it back
- loc2, err := cdsm.Insert("test1")
- if err != nil {
- t.Error(err)
- return
- }
- if loc != loc2 {
- t.Error("Unexpected insert position:", loc, loc2)
- return
- }
- // Check free error
- record, err := dsm.physicalSlotsSf.Get(1)
- if err != nil {
- t.Error(err)
- return
- }
- err = cdsm.Free(loc2)
- if sfe, ok := err.(*file.StorageFileError); !ok || sfe.Type != file.ErrAlreadyInUse {
- t.Error("Unexpected free result:", err)
- return
- }
- dsm.physicalSlotsSf.ReleaseInUse(record)
- // Check that nothing was lost
- if err := cdsm.Fetch(loc2, &ret); err != nil || ret != "test1" {
- t.Error("Unexpected fetch result:", ret, err)
- return
- }
- if err := cdsm.Free(loc2); err != nil {
- t.Error(err)
- return
- }
- if err := cdsm.Fetch(loc2, &ret); err.(*ManagerError).Type != ErrSlotNotFound {
- t.Error("Unexpected fetch result:", err)
- return
- }
- if err = cdsm.Close(); err != nil {
- t.Error(err)
- }
- }
- func TestCachedDiskStorageManagerCacheManagement(t *testing.T) {
- var ret string
- dsm := NewDiskStorageManager(DBDIR+"/ctest3", false, false, true, true)
- cdsm := NewCachedDiskStorageManager(dsm, 3)
- // Event though the cache is empty make sure we can still retrieve empty entries
- entry := cdsm.removeOldestFromCache()
- if entry == nil {
- t.Error("Unexpected removeOldestFromCache result:", entry)
- return
- }
- // Insert values
- loc1, _ := cdsm.Insert("test1")
- loc2, _ := cdsm.Insert("test2")
- loc3, _ := cdsm.Insert("test3")
- loc4, _ := cdsm.Insert("test4")
- // Load all entries into the cache
- cdsm.Fetch(loc1, &ret)
- cdsm.Fetch(loc2, &ret)
- cdsm.Fetch(loc3, &ret)
- // Make sure all cache entries are there
- if _, ok := cdsm.cache[loc1]; !ok {
- t.Error("Cache entry should be available")
- return
- }
- if _, ok := cdsm.cache[loc2]; !ok {
- t.Error("Cache entry should be available")
- return
- }
- if _, ok := cdsm.cache[loc3]; !ok {
- t.Error("Cache entry should be available")
- return
- }
- // Now fetch one more and see that the oldest entry gets removed
- cdsm.Fetch(loc4, &ret)
- if _, ok := cdsm.cache[loc1]; ok {
- t.Error("Cache entry should not be available")
- return
- }
- // Check that the last accessed entry is on the last position in the list
- if cdsm.lastentry.location != loc4 {
- t.Error("Unexpected last entry:", cdsm.firstentry.location)
- return
- }
- cdsm.Fetch(loc2, &ret)
- if cdsm.lastentry.location != loc2 {
- t.Error("Unexpected last entry:", cdsm.firstentry.location)
- return
- }
- if cdsm.firstentry.location != loc3 {
- t.Error("Unexpected first entry:", cdsm.firstentry.location)
- return
- }
- record, err := dsm.physicalSlotsSf.Get(1)
- if err != nil {
- t.Error(err)
- return
- }
- // Check we get an error when attempting to update the physical record
- // because we want to remove an entry from the list
- cdsm.Update(loc3, "test9")
- cdsm.Update(loc2, "test9")
- cdsm.Update(loc4, "test9")
- if cdsm.firstentry.location != loc3 {
- t.Error("Unexpected first entry:", cdsm.firstentry.location)
- return
- }
- dsm.physicalSlotsSf.ReleaseInUse(record)
- entry = cdsm.removeOldestFromCache()
- if entry.location != loc3 {
- t.Error("Unexpected removeOldestFromCache result:", entry, err)
- return
- }
- if err = cdsm.Close(); err != nil {
- t.Error(err)
- }
- }
|