summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Pointner <equinox@spreadspace.org>2017-04-30 01:16:50 +0200
committerChristian Pointner <equinox@spreadspace.org>2017-04-30 01:16:50 +0200
commit1ecc099e6ef9046be6f11d48548e7d5e7ac4c33f (patch)
tree4b981813cbfca4a3d8a1690bb9e6c05962dbeaee
parentadded test cases for open and creation (diff)
introduced read-only mode
-rw-r--r--src/hub/src/spreadspace.org/sfive-hub/s5hub.go3
-rw-r--r--src/hub/src/spreadspace.org/sfive/s5srv.go4
-rw-r--r--src/hub/src/spreadspace.org/sfive/s5store.go15
-rw-r--r--src/hub/src/spreadspace.org/sfive/s5store_test.go69
4 files changed, 62 insertions, 29 deletions
diff --git a/src/hub/src/spreadspace.org/sfive-hub/s5hub.go b/src/hub/src/spreadspace.org/sfive-hub/s5hub.go
index 2bb436f..4028f3f 100644
--- a/src/hub/src/spreadspace.org/sfive-hub/s5hub.go
+++ b/src/hub/src/spreadspace.org/sfive-hub/s5hub.go
@@ -45,6 +45,7 @@ var s5hl = log.New(os.Stderr, "[s5hub]\t", log.LstdFlags)
func main() {
db := flag.String("db", "/var/lib/sfive/db.bolt", "path to the database file")
+ readOnly := flag.Bool("read-only", false, "open database in read-only mode")
pipe := flag.String("pipe", "/var/run/sfive/pipe", "path to the unix pipe for the pipeserver")
ppipe := flag.String("pipegram", "/var/run/sfive/pipegram", "path to the unix datagram pipe for the pipeserver")
startPipe := flag.Bool("start-pipe-server", true, "start a connection oriented pipe server; see option pipe")
@@ -68,7 +69,7 @@ func main() {
return
}
- srv, err := sfive.NewServer(*db)
+ srv, err := sfive.NewServer(*db, *readOnly)
if err != nil {
s5hl.Fatalf(err.Error())
}
diff --git a/src/hub/src/spreadspace.org/sfive/s5srv.go b/src/hub/src/spreadspace.org/sfive/s5srv.go
index 8db3c7e..23429a9 100644
--- a/src/hub/src/spreadspace.org/sfive/s5srv.go
+++ b/src/hub/src/spreadspace.org/sfive/s5srv.go
@@ -158,10 +158,10 @@ func (srv Server) Close() {
s5l.Printf("server: finished\n")
}
-func NewServer(dbPath string) (server *Server, err error) {
+func NewServer(dbPath string, readOnly bool) (server *Server, err error) {
// TODO read configuration and create instance with correct settings
server = new(Server)
- server.store, err = NewStore(dbPath)
+ server.store, err = NewStore(dbPath, readOnly)
if err != nil {
return
}
diff --git a/src/hub/src/spreadspace.org/sfive/s5store.go b/src/hub/src/spreadspace.org/sfive/s5store.go
index ea114c7..d2a0734 100644
--- a/src/hub/src/spreadspace.org/sfive/s5store.go
+++ b/src/hub/src/spreadspace.org/sfive/s5store.go
@@ -59,15 +59,15 @@ type Store struct {
db *bolt.DB
}
-func checkDb(dbPath string) (db *bolt.DB, version int, hubUuid string, err error) {
+func checkDb(dbPath string, readOnly bool) (db *bolt.DB, version int, hubUuid string, err error) {
if _, err = os.Stat(dbPath); err != nil {
if os.IsNotExist(err) {
err = nil
}
return
}
-
- db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
+ opts := &bolt.Options{Timeout: 100 * time.Millisecond, ReadOnly: readOnly}
+ db, err = bolt.Open(dbPath, 0600, opts)
if err != nil {
return
}
@@ -106,7 +106,7 @@ func checkDb(dbPath string) (db *bolt.DB, version int, hubUuid string, err error
}
func initDb(dbPath string) (db *bolt.DB, version int, hubUuid string, err error) {
- db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 1 * time.Second})
+ db, err = bolt.Open(dbPath, 0600, &bolt.Options{Timeout: 100 * time.Millisecond})
if err != nil {
return
}
@@ -484,8 +484,8 @@ func (st Store) GetStoreId() string {
return st.hubUuid
}
-func NewStore(dbPath string) (Store, error) {
- db, version, hubid, err := checkDb(dbPath)
+func NewStore(dbPath string, readOnly bool) (Store, error) {
+ db, version, hubid, err := checkDb(dbPath, readOnly)
if err != nil {
return Store{}, err
}
@@ -493,6 +493,9 @@ func NewStore(dbPath string) (Store, error) {
if db != nil {
s5l.Printf("store: opened (UUID: %s)", hubid)
} else {
+ if readOnly {
+ return Store{}, errors.New("store: failed to open, requested read-only mode but file does not exist.")
+ }
db, version, hubid, err = initDb(dbPath)
if err != nil {
return Store{}, err
diff --git a/src/hub/src/spreadspace.org/sfive/s5store_test.go b/src/hub/src/spreadspace.org/sfive/s5store_test.go
index 02ab727..bda0a5e 100644
--- a/src/hub/src/spreadspace.org/sfive/s5store_test.go
+++ b/src/hub/src/spreadspace.org/sfive/s5store_test.go
@@ -64,7 +64,7 @@ func TestMain(m *testing.M) {
func TestOpen(t *testing.T) {
// non-existing directory
- if _, err := NewStore("/nonexistend/db.bolt"); err == nil {
+ if _, err := NewStore("/nonexistend/db.bolt", false); err == nil {
t.Fatalf("opening store in nonexisting directory should throw an error")
}
@@ -73,8 +73,8 @@ func TestOpen(t *testing.T) {
if err := os.MkdirAll(__boltPath, 0700); err != nil {
t.Fatalf("unexpected error: %v", err)
}
- if _, err := NewStore(__boltPath); err == nil {
- t.Fatalf("opening store using a directory should throw an error: %v", err)
+ if _, err := NewStore(__boltPath, false); err == nil {
+ t.Fatalf("opening store using a directory should throw an error")
}
// exisitng but non-database file
@@ -85,13 +85,13 @@ func TestOpen(t *testing.T) {
io.WriteString(f, "this is not a bolt db.")
f.Close()
}
- if _, err := NewStore(__boltPath); err == nil {
- t.Fatalf("opening store using a invalid database should throw an error: %v", err)
+ if _, err := NewStore(__boltPath, false); err == nil {
+ t.Fatalf("opening store using a invalid database should throw an error")
}
// bolt db with wrong layout
os.Remove(__boltPath)
- if db, err := bolt.Open(__boltPath, 0600, &bolt.Options{Timeout: 1 * time.Second}); err != nil {
+ if db, err := bolt.Open(__boltPath, 0600, &bolt.Options{Timeout: 100 * time.Millisecond}); err != nil {
t.Fatalf("unexpected error: %v", err)
} else {
err = db.Update(func(tx *bolt.Tx) error {
@@ -107,13 +107,13 @@ func TestOpen(t *testing.T) {
t.Fatalf("unexpected error: %v", err)
}
}
- if _, err := NewStore(__boltPath); err == nil {
- t.Fatalf("opening store using a invalid database should throw an error: %v", err)
+ if _, err := NewStore(__boltPath, false); err == nil {
+ t.Fatalf("opening store using a invalid database should throw an error")
}
// bolt db with wrong version
os.Remove(__boltPath)
- if db, err := bolt.Open(__boltPath, 0600, &bolt.Options{Timeout: 1 * time.Second}); err != nil {
+ if db, err := bolt.Open(__boltPath, 0600, &bolt.Options{Timeout: 100 * time.Millisecond}); err != nil {
t.Fatalf("unexpected error: %v", err)
} else {
err = db.Update(func(tx *bolt.Tx) error {
@@ -134,13 +134,13 @@ func TestOpen(t *testing.T) {
t.Fatalf("unexpected error: %v", err)
}
}
- if _, err := NewStore(__boltPath); err == nil {
- t.Fatalf("opening store with the wrong database version should throw an error: %v", err)
+ if _, err := NewStore(__boltPath, false); err == nil {
+ t.Fatalf("opening store with the wrong database version should throw an error")
}
// bolt db empty UUID
os.Remove(__boltPath)
- if db, err := bolt.Open(__boltPath, 0600, &bolt.Options{Timeout: 1 * time.Second}); err != nil {
+ if db, err := bolt.Open(__boltPath, 0600, &bolt.Options{Timeout: 100 * time.Millisecond}); err != nil {
t.Fatalf("unexpected error: %v", err)
} else {
err = db.Update(func(tx *bolt.Tx) error {
@@ -165,32 +165,36 @@ func TestOpen(t *testing.T) {
t.Fatalf("unexpected error: %v", err)
}
}
- if _, err := NewStore(__boltPath); err == nil {
- t.Fatalf("opening store with empty UUID should throw an error: %v", err)
+ if _, err := NewStore(__boltPath, false); err == nil {
+ t.Fatalf("opening store with empty UUID should throw an error")
}
// create new bolt-db and reopen it
os.Remove(__boltPath)
- store, err := NewStore(__boltPath)
+ store, err := NewStore(__boltPath, false)
if err != nil {
t.Fatalf("creating new store failed: %v", err)
}
createdUuid := store.hubUuid
store.Close()
- store, err = NewStore(__boltPath)
+ store, err = NewStore(__boltPath, false)
if err != nil {
t.Fatalf("re-opening existing store failed: %v", err)
}
if createdUuid != store.hubUuid {
t.Fatalf("UUID of opened store differs from the one previously generated: '%s' != '%s'", createdUuid, store.hubUuid)
}
+
+ if _, err := NewStore(__boltPath, false); err == nil {
+ t.Fatalf("opening already opened database should throw an error")
+ }
store.Close()
}
// func TestAppend(t *testing.T) {
// os.Remove(__boltPath)
-// store, err := NewStore(__boltPath)
+// store, err := NewStore(__boltPath, false)
// if err != nil {
// t.Fatalf("Failed to initialize: %v", err)
// }
@@ -210,7 +214,7 @@ func TestOpen(t *testing.T) {
// func TestGetUpdatesAfter(t *testing.T) {
// os.Remove(__boltPath)
-// store, err := NewStore(__boltPath)
+// store, err := NewStore(__boltPath, false)
// if err != nil {
// t.Fatalf("Failed to initialize: %v", err)
// }
@@ -231,6 +235,31 @@ func TestOpen(t *testing.T) {
// t.Logf("got updates (err %v):\n%#v", err, res)
// }
+func TestReadOnly(t *testing.T) {
+ // create read-only db from not-existing file must fail
+ os.Remove(__boltPath)
+ if _, err := NewStore(__boltPath, true); err == nil {
+ t.Fatalf("creating a read-only database should throw an error")
+ }
+
+ // open read-only db from existing file must succeed
+ store, err := NewStore(__boltPath, false)
+ if err != nil {
+ t.Fatalf("unexpected error: %v", err)
+ }
+ store.Close()
+
+ store, err = NewStore(__boltPath, false)
+ if err != nil {
+ t.Fatalf("opening existing store in read-only mode failed: %v", err)
+ }
+ store.Close()
+
+ //
+ // TODO: test append on read-only store
+ //
+}
+
// func generateDataUpdateFull(n int) (data []DataUpdateFull) {
// hostnames := []string{"streamer1", "streamer2"}
// contents := []string{"av", "audio"}
@@ -284,7 +313,7 @@ func TestOpen(t *testing.T) {
// func BenchmarkAppendMany(b *testing.B) {
// os.Remove(__boltPath)
-// store, err := NewStore(__boltPath)
+// store, err := NewStore(__boltPath, false)
// if err != nil {
// b.Fatalf("Failed to initialize: %v", err)
// }
@@ -300,7 +329,7 @@ func TestOpen(t *testing.T) {
// func BenchmarkGetUpdatesAfter(b *testing.B) {
// os.Remove(__boltPath)
-// store, err := NewStore(__boltPath)
+// store, err := NewStore(__boltPath, false)
// if err != nil {
// b.Fatalf("Failed to initialize: %v", err)
// }