Simplified interface

This commit is contained in:
Eduard Urbach 2023-07-17 21:57:14 +02:00
parent ec5871289b
commit 47ec84e8ba
Signed by: akyoto
GPG Key ID: C874F672B1AF20C0
6 changed files with 28 additions and 29 deletions

View File

@ -54,6 +54,11 @@ func New[T any](namespace string, storage Storage[T]) (Collection[T], error) {
return c, storage.Init(c)
}
// NewFile creates a new collection with the given name and the File storage system.
func NewFile[T any](namespace string) (Collection[T], error) {
return New[T](namespace, &File[T]{})
}
// All returns a channel of all objects in the collection.
func (c *collection[T]) All() <-chan *T {
channel := make(chan *T)

View File

@ -1,4 +1,4 @@
package storage
package ocean
import (
"bufio"
@ -10,8 +10,6 @@ import (
"sort"
"sync/atomic"
"time"
"git.akyoto.dev/go/ocean"
)
const (
@ -20,12 +18,12 @@ const (
)
type File[T any] struct {
collection ocean.StorageData
collection StorageData
dirty atomic.Uint32
sync chan struct{}
}
func (fs *File[T]) Init(c ocean.StorageData) error {
func (fs *File[T]) Init(c StorageData) error {
fs.collection = c
fs.sync = make(chan struct{})

View File

@ -1,24 +1,18 @@
package storage_test
package ocean_test
import (
"testing"
"git.akyoto.dev/go/assert"
"git.akyoto.dev/go/ocean"
"git.akyoto.dev/go/ocean/storage"
)
var _ ocean.Storage[string] = (*storage.File[string])(nil)
type User struct {
Name string `json:"name"`
}
var _ ocean.Storage[string] = (*ocean.File[string])(nil)
func TestFilePersistence(t *testing.T) {
users, err := ocean.New[User]("test", &storage.File[User]{})
users, err := ocean.NewFile[User]("test")
assert.Nil(t, err)
defer users.Sync()
defer users.Clear()
users.Set("1", &User{Name: "User 1"})
@ -26,7 +20,7 @@ func TestFilePersistence(t *testing.T) {
users.Set("3", &User{Name: "User 3"})
users.Sync()
reload, err := ocean.New[User]("test", &storage.File[User]{})
reload, err := ocean.NewFile[User]("test")
assert.Nil(t, err)
user, err := reload.Get("1")

View File

@ -11,27 +11,29 @@ go get git.akyoto.dev/go/ocean
## Example
```go
// Define the User type
// User type
type User struct { Name string }
// Create a collection in ~/.ocean/myapp/User.dat
users := ocean.New[User]("myapp", &storage.File[User]{})
// Create ~/.ocean/myapp/User.dat
users := ocean.NewFile[User]("myapp")
// Store some data
// Write
users.Set("1", &User{Name: "User 1"})
users.Set("2", &User{Name: "User 2"})
users.Set("3", &User{Name: "User 3"})
// Read from memory
first, err := users.Get("1")
// Read
a, err := users.Get("1")
b, err := users.Get("2")
c, err := users.Get("3")
// Iterate over all users
// Iterate
for user := range users.All() {
fmt.Println(user.Name)
}
```
## File format
## Format
```json
1
@ -57,17 +59,17 @@ BenchmarkNew-12 48838576 22.89 ns/op 80 B/op
You can specify `nil` as the storage system which will keep data in RAM only.
### storage.File
### ocean.File
`storage.File` uses a single file to store all records.
`ocean.File` uses a single file to store all records.
Writes using `Set(key, value)` are async and only mark the collection as "dirty" which is very quick.
The sync to disk happens shortly afterwards.
Every collection uses one goroutine to check the "dirty" flag, write the new contents to disk and reset the flag.
The biggest advantage of `storage.File` is that it scales well with the number of requests:
The biggest advantage of `ocean.File` is that it scales well with the number of requests:
Suppose `n` is the number of write requests and `io` is the time it takes for one write. Immediate storage would require `O(n * io)` time to complete all writes but the async behavior makes it `O(n)`.
Suppose `n` is the number of write requests and `io` is the time it takes for one write. Immediate ocean would require `O(n * io)` time to complete all writes but the async behavior makes it `O(n)`.
You should use `storage.File` if you have a permanently running process such as a web server where end users expect quick responses and background work can happen after the user request has already been dealt with.
You should use `ocean.File` if you have a permanently running process such as a web server where end users expect quick responses and background work can happen after the user request has already been dealt with.
Make sure you `defer collection.Sync()` to ensure that queued writes will be handled when the process ends.

View File

@ -1,4 +1,4 @@
package storage
package ocean
type keyValue struct {
key string