From 658cd6a8a3c05bbd3f17ccee9cc036cf5cd9dbcc Mon Sep 17 00:00:00 2001 From: Eduard Urbach Date: Wed, 12 Jul 2023 10:58:20 +0200 Subject: [PATCH] Improved interfaces --- Benchmarks_test.go | 2 +- Collection.go | 11 ++++++----- README.md | 12 +++++++++++- Storage.go | 2 +- StorageData.go | 9 +++++++++ storage/Directory.go | 21 ++++++++++++++++----- storage/File.go | 4 ++-- 7 files changed, 46 insertions(+), 15 deletions(-) create mode 100644 StorageData.go diff --git a/Benchmarks_test.go b/Benchmarks_test.go index 6a1e9a9..b9a0b0f 100644 --- a/Benchmarks_test.go +++ b/Benchmarks_test.go @@ -71,7 +71,7 @@ func BenchmarkDelete(b *testing.B) { func BenchmarkNew(b *testing.B) { b.RunParallel(func(pb *testing.PB) { for pb.Next() { - ocean.New[User]("test", nil) + _, _ = ocean.New[User]("test", nil) } }) } diff --git a/Collection.go b/Collection.go index 84c76e8..5dde7fa 100644 --- a/Collection.go +++ b/Collection.go @@ -10,13 +10,10 @@ import ( type Collection[T any] interface { All() <-chan *T Clear() - Data() *sync.Map Delete(key string) Exists(key string) bool Filter(func(*T) bool) <-chan *T Get(key string) (value *T, err error) - Name() string - Root() string Set(key string, value *T) Sync() } @@ -30,7 +27,7 @@ type collection[T any] struct { } // New creates a new collection with the given name. -func New[T any](namespace string, storage Storage[T]) (*collection[T], error) { +func New[T any](namespace string, storage Storage[T]) (Collection[T], error) { name := reflect.TypeOf((*T)(nil)).Elem().Name() c := &collection[T]{ name: name, @@ -94,7 +91,11 @@ func (c *collection[T]) Delete(key string) { return } - c.storage.Delete(key) + err := c.storage.Delete(key) + + if err != nil { + panic(err) + } } // Exists returns whether or not the key exists. diff --git a/README.md b/README.md index 6b8530f..54df010 100644 --- a/README.md +++ b/README.md @@ -15,7 +15,8 @@ go get git.akyoto.dev/go/ocean type User struct { Name string } // Create a new collection -users := ocean.New[User]("todolist", &storage.File[User]{}) +todolist := ocean.New("todolist") +users := todolist.NewCollection[User](&storage.File[User]{}) // Store some data users.Set("1", &User{Name: "User 1"}) @@ -44,6 +45,15 @@ Data will be stored in `~/.ocean/todolist/User.dat`. {"name":"User 3"} ``` +## Benchmarks + +``` +BenchmarkGet-12 275126157 4.462 ns/op 0 B/op 0 allocs/op +BenchmarkSet-12 4796011 251.0 ns/op 32 B/op 2 allocs/op +BenchmarkDelete-12 471913158 2.530 ns/op 0 B/op 0 allocs/op +BenchmarkNew-12 48838576 22.89 ns/op 80 B/op 1 allocs/op +``` + ## Usage 1. Create all the collections you need at the start diff --git a/Storage.go b/Storage.go index ec163ab..e23091c 100644 --- a/Storage.go +++ b/Storage.go @@ -1,7 +1,7 @@ package ocean type Storage[T any] interface { - Init(c Collection[T]) error + Init(data StorageData) error Delete(key string) error Set(key string, value *T) error Sync() diff --git a/StorageData.go b/StorageData.go new file mode 100644 index 0000000..eecf1e1 --- /dev/null +++ b/StorageData.go @@ -0,0 +1,9 @@ +package ocean + +import "sync" + +type StorageData interface { + Data() *sync.Map + Name() string + Root() string +} diff --git a/storage/Directory.go b/storage/Directory.go index f05da46..c1a40b1 100644 --- a/storage/Directory.go +++ b/storage/Directory.go @@ -10,15 +10,20 @@ import ( // Directory creates a directory and stores every record in a separate file. type Directory[T any] struct { - collection ocean.Collection[T] + collection ocean.StorageData directory string } // Init loads all existing records from the directory. -func (ds *Directory[T]) Init(c ocean.Collection[T]) error { +func (ds *Directory[T]) Init(c ocean.StorageData) error { ds.collection = c ds.directory = filepath.Join(c.Root(), c.Name()) - os.Mkdir(ds.directory, 0700) + err := os.Mkdir(ds.directory, 0700) + + if err != nil { + return err + } + return ds.read() } @@ -29,7 +34,13 @@ func (ds *Directory[T]) Set(key string, value *T) error { // Delete deletes the file for the given key. func (ds *Directory[T]) Delete(key string) error { - return os.Remove(ds.keyFile(key)) + err := os.Remove(ds.keyFile(key)) + + if os.IsNotExist(err) { + return nil + } + + return err } // Sync does nothing when using directory storage. @@ -81,7 +92,7 @@ func (ds *Directory[T]) readFile(fileName string) error { } // writeFile writes the value for the key to disk as a JSON file. -func (ds *Directory[T]) writeFile(key string, value *T) error { +func (ds *Directory[T]) writeFile(key string, value any) error { fileName := ds.keyFile(key) file, err := os.OpenFile(fileName, os.O_CREATE|os.O_WRONLY|os.O_TRUNC, 0600) diff --git a/storage/File.go b/storage/File.go index 9fe49f6..d0ba9ea 100644 --- a/storage/File.go +++ b/storage/File.go @@ -17,12 +17,12 @@ import ( const diskWriteInterval = 100 * time.Millisecond type File[T any] struct { - collection ocean.Collection[T] + collection ocean.StorageData dirty atomic.Uint32 sync chan struct{} } -func (fs *File[T]) Init(c ocean.Collection[T]) error { +func (fs *File[T]) Init(c ocean.StorageData) error { fs.collection = c fs.sync = make(chan struct{})