commit 7ea16f9137b46ff746f6ba40d3afc7b305d98f87
parent 5769abf3366f78392dd9ad59607fde3bfe3e63b3
Author: lash <dev@holbrook.no>
Date: Sun, 22 Sep 2024 16:21:36 +0100
Add read only modifier to database
Diffstat:
3 files changed, 37 insertions(+), 7 deletions(-)
diff --git a/db/gdbm/gdbm.go b/db/gdbm/gdbm.go
@@ -3,6 +3,7 @@ package gdbm
import (
"context"
"errors"
+ "fmt"
"os"
gdbm "github.com/graygnuorg/go-gdbm"
@@ -14,6 +15,7 @@ import (
type gdbmDb struct {
*db.DbBase
conn *gdbm.Database
+ readOnly bool
prefix uint8
}
@@ -25,6 +27,18 @@ func NewGdbmDb() *gdbmDb {
return db
}
+// WithReadOnly sets database as read only.
+//
+// There may exist more than one instance of read-only
+// databases to the same file at the same time.
+// However, only one single write database.
+//
+// Readonly cannot be set when creating a new database.
+func(gdb *gdbmDb) WithReadOnly() *gdbmDb {
+ gdb.readOnly = true
+ return gdb
+}
+
// String implements the string interface.
func(gdb *gdbmDb) String() string {
fn, err := gdb.conn.FileName()
@@ -41,18 +55,30 @@ func(gdb *gdbmDb) Connect(ctx context.Context, connStr string) error {
return nil
}
var db *gdbm.Database
+ cfg := gdbm.DatabaseConfig{
+ FileName: connStr,
+ Flags: gdbm.OF_NOLOCK | gdbm.OF_PREREAD,
+ FileMode: 0600,
+ }
+
_, err := os.Stat(connStr)
if err != nil {
if !errors.Is(err.(*os.PathError).Unwrap(), os.ErrNotExist) {
- return err
+ return fmt.Errorf("db path lookup err: %v", err)
}
- db, err = gdbm.Open(connStr, gdbm.ModeWrcreat)
+ if gdb.readOnly {
+ return fmt.Errorf("cannot open new database readonly")
+ }
+ cfg.Mode = gdbm.ModeReader | gdbm.ModeWrcreat
} else {
- db, err = gdbm.Open(connStr, gdbm.ModeWriter | gdbm.ModeReader)
+ cfg.Mode = gdbm.ModeReader
+ if !gdb.readOnly {
+ cfg.Mode |= gdbm.ModeWriter
+ }
}
-
+ db, err = gdbm.OpenConfig(cfg)
if err != nil {
- return err
+ return fmt.Errorf("db open err: %v", err)
}
logg.DebugCtxf(ctx, "gdbm connected", "connstr", connStr)
gdb.conn = db
diff --git a/engine/db.go b/engine/db.go
@@ -244,7 +244,7 @@ func(en *DefaultEngine) ensurePersist() error {
} else {
en.ca = cac
}
- logg.Tracef("set persister", "st", st, "cac", cac)
+ logg.Tracef("set persister", "st", st, "cac", cac, "session", en.cfg.SessionId)
en.pe = en.pe.WithContent(st, cac)
err := en.pe.Load(en.cfg.SessionId)
if err != nil {
diff --git a/state/state.go b/state/state.go
@@ -7,6 +7,10 @@ import (
"git.defalsify.org/vise.git/lang"
)
+const (
+ INPUT_LIMIT = 255
+)
+
var (
IndexError = fmt.Errorf("already at first index")
MaxLevel = 128
@@ -347,7 +351,7 @@ func(st *State) GetInput() ([]byte, error) {
// SetInput is used to record the latest client input.
func(st *State) SetInput(input []byte) error {
l := len(input)
- if l > 255 {
+ if l > INPUT_LIMIT {
return fmt.Errorf("input size %v too large (limit %v)", l, 255)
}
st.input = input