123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- /*
- * 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 (
- "bytes"
- "fmt"
- "sync"
- "devt.de/krotik/common/datautil"
- "devt.de/krotik/eliasdb/storage/file"
- )
- /*
- Special flags which cause the manager to return errors on specific function calls
- */
- const (
- AccessNotInCache = 1 // The address will not be accessible via FetchCached
- AccessFetchError = 2 // The address will not be accessible via Fetch
- AccessUpdateError = 3 // The address will not be accessible via Update
- AccessFreeError = 4 // The address will not be accessible via Free
- AccessInsertError = 5 // The address will not be accessible via Insert
- AccessCacheAndFetchError = 6 // The address will not be accessible via FetchCached nor Fetch
- AccessCacheAndFetchSeriousError = 7 // The address will not be accessible via FetchCached nor Fetch
- )
- /*
- MsmRetClose nil or the error which should be returned by a Close call
- */
- var MsmRetClose error
- /*
- MsmCallNumClose counter how often Close is called
- */
- var MsmCallNumClose int
- /*
- MsmRetFlush nil or the error which should be returned by a Flush call
- */
- var MsmRetFlush error
- /*
- MsmCallNumFlush counter how often Flush is called
- */
- var MsmCallNumFlush int
- /*
- MsmRetRollback nil or the error which should be returned by a Rollback call
- */
- var MsmRetRollback error
- /*
- MsmCallNumRollback counter how often Rollback is called
- */
- var MsmCallNumRollback int
- /*
- MemoryStorageManager data structure
- */
- type MemoryStorageManager struct {
- name string // Name of the storage manager
- Roots map[int]uint64 // Map of roots
- Data map[uint64]interface{} // Map of data
- mutex *sync.Mutex // Mutex to protect map operations
- LocCount uint64 // Counter for locations - Must start > 0
- AccessMap map[uint64]int // Special map to simulate access issues
- }
- /*
- NewMemoryStorageManager creates a new MemoryStorageManager
- */
- func NewMemoryStorageManager(name string) *MemoryStorageManager {
- // LocCount must start > 0 - so they can be stored in a Root. Roots with
- // the value 0 are considered empty. See also graph.getHTree which will
- // keep creating new HTrees if a Root is 0.
- return &MemoryStorageManager{name, make(map[int]uint64),
- make(map[uint64]interface{}), &sync.Mutex{}, 1, make(map[uint64]int)}
- }
- /*
- Name returns the name of the StorageManager instance.
- */
- func (msm *MemoryStorageManager) Name() string {
- return msm.name
- }
- /*
- Root returns a root value. Default (empty) value is 0.
- */
- func (msm *MemoryStorageManager) Root(root int) uint64 {
- msm.mutex.Lock()
- defer msm.mutex.Unlock()
- return msm.Roots[root]
- }
- /*
- SetRoot writes a root value.
- */
- func (msm *MemoryStorageManager) SetRoot(root int, val uint64) {
- msm.mutex.Lock()
- defer msm.mutex.Unlock()
- msm.Roots[root] = val
- }
- /*
- Insert inserts an object and return its storage location.
- */
- func (msm *MemoryStorageManager) Insert(o interface{}) (uint64, error) {
- msm.mutex.Lock()
- defer msm.mutex.Unlock()
- if msm.AccessMap[msm.LocCount] == AccessInsertError {
- return 0, file.NewStorageFileError(file.ErrAlreadyInUse, "", "<memory>")
- }
- loc := msm.LocCount
- msm.LocCount++
- msm.Data[loc] = o
- return loc, nil
- }
- /*
- Update updates a storage location.
- */
- func (msm *MemoryStorageManager) Update(loc uint64, o interface{}) error {
- msm.mutex.Lock()
- defer msm.mutex.Unlock()
- if msm.AccessMap[loc] == AccessUpdateError {
- return NewStorageManagerError(ErrSlotNotFound, fmt.Sprint("Location:", loc), msm.Name())
- }
- msm.Data[loc] = o
- return nil
- }
- /*
- Free frees a storage location.
- */
- func (msm *MemoryStorageManager) Free(loc uint64) error {
- msm.mutex.Lock()
- defer msm.mutex.Unlock()
- if msm.AccessMap[loc] == AccessFreeError {
- return NewStorageManagerError(ErrSlotNotFound, fmt.Sprint("Location:", loc), msm.Name())
- }
- delete(msm.Data, loc)
- return nil
- }
- /*
- Fetch fetches an object from a given storage location and writes it to
- a given data container.
- */
- func (msm *MemoryStorageManager) Fetch(loc uint64, o interface{}) error {
- var err error
- msm.mutex.Lock()
- defer msm.mutex.Unlock()
- if msm.AccessMap[loc] == AccessFetchError || msm.AccessMap[loc] == AccessCacheAndFetchError {
- return NewStorageManagerError(ErrSlotNotFound, fmt.Sprint("Location:", loc), msm.Name())
- } else if msm.AccessMap[loc] == AccessCacheAndFetchSeriousError {
- return file.NewStorageFileError(file.ErrAlreadyInUse, "", "<memory>")
- }
- if obj, ok := msm.Data[loc]; ok {
- err = datautil.CopyObject(obj, o)
- } else {
- err = NewStorageManagerError(ErrSlotNotFound, fmt.Sprint("Location:", loc), msm.Name())
- }
- return err
- }
- /*
- FetchCached fetches an object from a cache and returns its reference.
- Returns a storage.ErrNotInCache error if the entry is not in the cache.
- */
- func (msm *MemoryStorageManager) FetchCached(loc uint64) (interface{}, error) {
- msm.mutex.Lock()
- defer msm.mutex.Unlock()
- if msm.AccessMap[loc] == AccessNotInCache || msm.AccessMap[loc] == AccessCacheAndFetchError {
- return nil, NewStorageManagerError(ErrNotInCache, "", msm.Name())
- } else if msm.AccessMap[loc] == AccessCacheAndFetchSeriousError {
- return nil, file.NewStorageFileError(file.ErrAlreadyInUse, "", "<memory>")
- }
- return msm.Data[loc], nil
- }
- /*
- Flush writes all pending changes to disk.
- */
- func (msm *MemoryStorageManager) Flush() error {
- MsmCallNumFlush++
- return MsmRetFlush
- }
- /*
- Rollback cancels all pending changes which have not yet been written to disk.
- */
- func (msm *MemoryStorageManager) Rollback() error {
- MsmCallNumRollback++
- return MsmRetRollback
- }
- /*
- Close the StorageManager and write all pending changes to disk.
- */
- func (msm *MemoryStorageManager) Close() error {
- MsmCallNumClose++
- return MsmRetClose
- }
- /*
- Show a string representation of the storage manager.
- */
- func (msm *MemoryStorageManager) String() string {
- buf := new(bytes.Buffer)
- buf.WriteString(fmt.Sprintf("MemoryStorageManager %v\n", msm.name))
- for k, v := range msm.Data {
- buf.WriteString(fmt.Sprintf("%v - %v\n", k, v))
- }
- return buf.String()
- }
|