diff options
author | 2024-05-22 09:46:24 +0000 | |
---|---|---|
committer | 2024-05-22 11:46:24 +0200 | |
commit | 3d3e99ae52ff8895b840cbced2e55b5f849fd4be (patch) | |
tree | c646d5eb99368028a2fbdafbe2c4400059d8eed5 /vendor/codeberg.org/gruf/go-storage/memory | |
parent | --- (#2923) (diff) | |
download | gotosocial-3d3e99ae52ff8895b840cbced2e55b5f849fd4be.tar.xz |
[performance] update storage backend and make use of seek syscall when available (#2924)
* update to use go-storage/ instead of go-store/v2/storage/
* pull in latest version from codeberg
* remove test output :innocent:
* add code comments
* set the exclusive bit when creating new files in disk config
* bump to actual release version
* bump to v0.1.1 (tis a simple no-logic change)
* update readme
* only use a temporary read seeker when decoding video if required (should only be S3 now)
* use fastcopy library to use memory pooled buffers when calling TempFileSeeker()
* update to use seek call in serveFileRange()
Diffstat (limited to 'vendor/codeberg.org/gruf/go-storage/memory')
-rw-r--r-- | vendor/codeberg.org/gruf/go-storage/memory/memory.go | 253 |
1 files changed, 253 insertions, 0 deletions
diff --git a/vendor/codeberg.org/gruf/go-storage/memory/memory.go b/vendor/codeberg.org/gruf/go-storage/memory/memory.go new file mode 100644 index 000000000..55728b827 --- /dev/null +++ b/vendor/codeberg.org/gruf/go-storage/memory/memory.go @@ -0,0 +1,253 @@ +package memory + +import ( + "bytes" + "context" + "io" + "strings" + "sync" + + "codeberg.org/gruf/go-iotools" + "codeberg.org/gruf/go-storage" + + "codeberg.org/gruf/go-storage/internal" +) + +// ensure MemoryStorage conforms to storage.Storage. +var _ storage.Storage = (*MemoryStorage)(nil) + +// MemoryStorage is a storage implementation that simply stores key-value +// pairs in a Go map in-memory. The map is protected by a mutex. +type MemoryStorage struct { + ow bool // overwrites + fs map[string][]byte + mu sync.Mutex +} + +// Open opens a new MemoryStorage instance with internal map starting size. +func Open(size int, overwrites bool) *MemoryStorage { + return &MemoryStorage{ + ow: overwrites, + fs: make(map[string][]byte, size), + } +} + +// Clean: implements Storage.Clean(). +func (st *MemoryStorage) Clean(ctx context.Context) error { + // Check context still valid + if err := ctx.Err(); err != nil { + return err + } + + // Lock map. + st.mu.Lock() + + // Resize map to only necessary size in-mem. + fs := make(map[string][]byte, len(st.fs)) + for key, val := range st.fs { + fs[key] = val + } + st.fs = fs + + // Done with lock. + st.mu.Unlock() + + return nil +} + +// ReadBytes: implements Storage.ReadBytes(). +func (st *MemoryStorage) ReadBytes(ctx context.Context, key string) ([]byte, error) { + // Check context still valid. + if err := ctx.Err(); err != nil { + return nil, err + } + + // Lock map. + st.mu.Lock() + + // Check key in store. + b, ok := st.fs[key] + if ok { + + // COPY bytes. + b = copyb(b) + } + + // Done with lock. + st.mu.Unlock() + + if !ok { + return nil, internal.ErrWithKey(storage.ErrNotFound, key) + } + + return b, nil +} + +// ReadStream: implements Storage.ReadStream(). +func (st *MemoryStorage) ReadStream(ctx context.Context, key string) (io.ReadCloser, error) { + // Read value data from store. + b, err := st.ReadBytes(ctx, key) + if err != nil { + return nil, err + } + + // Wrap in readcloser. + r := bytes.NewReader(b) + return iotools.NopReadCloser(r), nil +} + +// WriteBytes: implements Storage.WriteBytes(). +func (st *MemoryStorage) WriteBytes(ctx context.Context, key string, b []byte) (int, error) { + // Check context still valid + if err := ctx.Err(); err != nil { + return 0, err + } + + // Lock map. + st.mu.Lock() + + // Check key in store. + _, ok := st.fs[key] + + if ok && !st.ow { + // Done with lock. + st.mu.Unlock() + + // Overwrites are disabled, return existing key error. + return 0, internal.ErrWithKey(storage.ErrAlreadyExists, key) + } + + // Write copy to store. + st.fs[key] = copyb(b) + + // Done with lock. + st.mu.Unlock() + + return len(b), nil +} + +// WriteStream: implements Storage.WriteStream(). +func (st *MemoryStorage) WriteStream(ctx context.Context, key string, r io.Reader) (int64, error) { + // Read all from reader. + b, err := io.ReadAll(r) + if err != nil { + return 0, err + } + + // Write in-memory data to store. + n, err := st.WriteBytes(ctx, key, b) + return int64(n), err +} + +// Stat: implements Storage.Stat(). +func (st *MemoryStorage) Stat(ctx context.Context, key string) (*storage.Entry, error) { + // Check context still valid + if err := ctx.Err(); err != nil { + return nil, err + } + + // Lock map. + st.mu.Lock() + + // Check key in store. + b, ok := st.fs[key] + + // Get entry size. + sz := int64(len(b)) + + // Done with lock. + st.mu.Unlock() + + if !ok { + return nil, nil + } + + return &storage.Entry{ + Key: key, + Size: sz, + }, nil +} + +// Remove: implements Storage.Remove(). +func (st *MemoryStorage) Remove(ctx context.Context, key string) error { + // Check context still valid + if err := ctx.Err(); err != nil { + return err + } + + // Lock map. + st.mu.Lock() + + // Check key in store. + _, ok := st.fs[key] + + if ok { + // Delete store key. + delete(st.fs, key) + } + + // Done with lock. + st.mu.Unlock() + + if !ok { + return internal.ErrWithKey(storage.ErrNotFound, key) + } + + return nil +} + +// WalkKeys: implements Storage.WalkKeys(). +func (st *MemoryStorage) WalkKeys(ctx context.Context, opts storage.WalkKeysOpts) error { + if opts.Step == nil { + panic("nil step fn") + } + + // Check context still valid. + if err := ctx.Err(); err != nil { + return err + } + + var err error + + // Lock map. + st.mu.Lock() + + // Ensure unlocked. + defer st.mu.Unlock() + + // Range all key-vals in hash map. + for key, val := range st.fs { + // Check for filtered prefix. + if opts.Prefix != "" && + !strings.HasPrefix(key, opts.Prefix) { + continue // ignore + } + + // Check for filtered key. + if opts.Filter != nil && + !opts.Filter(key) { + continue // ignore + } + + // Pass to provided step func. + err = opts.Step(storage.Entry{ + Key: key, + Size: int64(len(val)), + }) + if err != nil { + return err + } + } + + return err +} + +// copyb returns a copy of byte-slice b. +func copyb(b []byte) []byte { + if b == nil { + return nil + } + p := make([]byte, len(b)) + _ = copy(p, b) + return p +} |