// Basic in-memory object store // // Licensed under CC0 1.0 Universal: // https://creativecommons.org/publicdomain/zero/1.0/legalcode package objectstore import ( "crypto/sha256" "encoding/hex" "os" "sync" ) type memObject struct { payload string hash string } type memBucket struct { objects map[string]memObject // Map used to check if the hash already exists, also // storing the objectId to identify de duplicate hashes map[string]string } type MemObjectStore struct { sync.Mutex buckets map[string]memBucket } func NewMemBackend() *MemObjectStore { mos := &MemObjectStore{} mos.buckets = make(map[string]memBucket) return mos } func (mos *MemObjectStore) CreateObject(bucketId string, objectId string, payload []byte) error { mos.Lock() defer mos.Unlock() // Create bucket if it doesn't exist bucket, ok := mos.buckets[bucketId] if !ok { bucket = memBucket{} bucket.objects = make(map[string]memObject) bucket.hashes = make(map[string]string) mos.buckets[bucketId] = bucket } // Hash the object content hasher := sha256.New() hasher.Write(payload) hash := hex.EncodeToString(hasher.Sum(nil)) // Check for duplicates if objectId, dup := bucket.hashes[hash]; dup { return NewDuplicateError(objectId) } // Store the object object := memObject{ payload: string(payload), hash: hash, } bucket.objects[objectId] = object bucket.hashes[hash] = objectId return nil } func (mos *MemObjectStore) GetObject(bucketId string, objectId string) (string, error) { mos.Lock() defer mos.Unlock() bucket, ok := mos.buckets[bucketId] if !ok { return "", os.ErrNotExist } object, ok := bucket.objects[objectId] if !ok { return "", os.ErrNotExist } return object.payload, nil } func (mos *MemObjectStore) DeleteObject(bucketId string, objectId string) error { mos.Lock() defer mos.Unlock() bucket, ok := mos.buckets[bucketId] if !ok { return os.ErrNotExist } object, ok := bucket.objects[objectId] if !ok { return os.ErrNotExist } // Delete both, object and hash delete(bucket.objects, objectId) delete(bucket.hashes, object.hash) // Delete the bucket if it's empty if len(bucket.objects) == 0 { delete(mos.buckets, bucketId) } return nil }