From 3adb203df289e48249b8b7b8b60780f8f118bf4f Mon Sep 17 00:00:00 2001
From: Hans Moog <hm@mkjc.net>
Date: Tue, 30 Jul 2019 15:54:04 +0200
Subject: [PATCH] Feat: changed database to use a single badger instance with
 prefixes

---
 packages/database/badger_instance.go | 53 +++++++++++++++++++
 packages/database/database.go        | 78 +++++++---------------------
 packages/database/interfaces.go      |  2 -
 3 files changed, 71 insertions(+), 62 deletions(-)
 create mode 100644 packages/database/badger_instance.go

diff --git a/packages/database/badger_instance.go b/packages/database/badger_instance.go
new file mode 100644
index 00000000..5670ba6d
--- /dev/null
+++ b/packages/database/badger_instance.go
@@ -0,0 +1,53 @@
+package database
+
+import (
+	"os"
+	"sync"
+
+	"github.com/dgraph-io/badger"
+	"github.com/dgraph-io/badger/options"
+)
+
+var instance *badger.DB
+
+var openLock sync.Mutex
+
+func GetBadgerInstance() (result *badger.DB, err error) {
+	openLock.Lock()
+
+	if instance == nil {
+		directory := *DIRECTORY.Value
+
+		if _, osErr := os.Stat(directory); osErr != nil {
+			err = osErr
+
+			return
+		} else if os.IsNotExist(err) {
+			if osErr := os.Mkdir(directory, 0700); osErr != nil {
+				err = osErr
+
+				return
+			}
+		}
+
+		opts := badger.DefaultOptions(directory)
+		opts.Logger = &logger{}
+		opts.Truncate = true
+		opts.TableLoadingMode = options.MemoryMap
+
+		db, badgerErr := badger.Open(opts)
+		if err != nil {
+			err = badgerErr
+
+			return
+		}
+
+		instance = db
+	}
+
+	openLock.Unlock()
+
+	result = instance
+
+	return
+}
diff --git a/packages/database/database.go b/packages/database/database.go
index ec49d1f7..4a0e9657 100644
--- a/packages/database/database.go
+++ b/packages/database/database.go
@@ -1,12 +1,9 @@
 package database
 
 import (
-	"os"
-	"path/filepath"
 	"sync"
 
 	"github.com/dgraph-io/badger"
-	"github.com/dgraph-io/badger/options"
 )
 
 var databasesByName = make(map[string]*databaseImpl)
@@ -17,6 +14,7 @@ var ErrKeyNotFound = badger.ErrKeyNotFound
 type databaseImpl struct {
 	db       *badger.DB
 	name     string
+	prefix   []byte
 	openLock sync.Mutex
 }
 
@@ -28,50 +26,24 @@ func Get(name string) (Database, error) {
 		return database, nil
 	}
 
-	database := &databaseImpl{
-		db:   nil,
-		name: name,
-	}
-	if err := database.Open(); err != nil {
+	badgerInstance, err := GetBadgerInstance()
+	if err != nil {
 		return nil, err
 	}
 
+	database := &databaseImpl{
+		db:     badgerInstance,
+		name:   name,
+		prefix: []byte(name + "_"),
+	}
+
 	databasesByName[name] = database
 
 	return databasesByName[name], nil
 }
 
-func (this *databaseImpl) Open() error {
-	this.openLock.Lock()
-	defer this.openLock.Unlock()
-
-	if this.db == nil {
-		directory := *DIRECTORY.Value
-
-		if _, err := os.Stat(directory); os.IsNotExist(err) {
-			if err := os.Mkdir(directory, 0700); err != nil {
-				return err
-			}
-		}
-
-		opts := badger.DefaultOptions(filepath.Join(directory, this.name))
-
-		opts.Logger = &logger{}
-		opts.Truncate = true
-		opts.TableLoadingMode = options.MemoryMap
-
-		db, err := badger.Open(opts)
-		if err != nil {
-			return err
-		}
-		this.db = db
-	}
-
-	return nil
-}
-
 func (this *databaseImpl) Set(key []byte, value []byte) error {
-	if err := this.db.Update(func(txn *badger.Txn) error { return txn.Set(key, value) }); err != nil {
+	if err := this.db.Update(func(txn *badger.Txn) error { return txn.Set(append(this.prefix, key...), value) }); err != nil {
 		return err
 	}
 
@@ -80,7 +52,7 @@ func (this *databaseImpl) Set(key []byte, value []byte) error {
 
 func (this *databaseImpl) Contains(key []byte) (bool, error) {
 	err := this.db.View(func(txn *badger.Txn) error {
-		_, err := txn.Get(key)
+		_, err := txn.Get(append(this.prefix, key...))
 		if err != nil {
 			return err
 		}
@@ -99,7 +71,7 @@ func (this *databaseImpl) Get(key []byte) ([]byte, error) {
 	var result []byte = nil
 
 	err := this.db.View(func(txn *badger.Txn) error {
-		item, err := txn.Get(key)
+		item, err := txn.Get(append(this.prefix, key...))
 		if err != nil {
 			return err
 		}
@@ -116,7 +88,7 @@ func (this *databaseImpl) Get(key []byte) ([]byte, error) {
 
 func (this *databaseImpl) Delete(key []byte) error {
 	err := this.db.Update(func(txn *badger.Txn) error {
-		err := txn.Delete(key)
+		err := txn.Delete(append(this.prefix, key...))
 		return err
 	})
 	return err
@@ -124,8 +96,11 @@ func (this *databaseImpl) Delete(key []byte) error {
 
 func (this *databaseImpl) ForEach(consumer func([]byte, []byte)) error {
 	err := this.db.View(func(txn *badger.Txn) error {
+		iteratorOptions := badger.DefaultIteratorOptions
+		iteratorOptions.Prefix = this.prefix
+
 		// create an iterator the default options
-		it := txn.NewIterator(badger.DefaultIteratorOptions)
+		it := txn.NewIterator(iteratorOptions)
 		defer it.Close()
 
 		// loop through every key-value-pair and call the function
@@ -137,26 +112,9 @@ func (this *databaseImpl) ForEach(consumer func([]byte, []byte)) error {
 				return err
 			}
 
-			consumer(item.Key(), value)
+			consumer(item.Key()[len(this.prefix):], value)
 		}
 		return nil
 	})
 	return err
 }
-
-func (this *databaseImpl) Close() error {
-	this.openLock.Lock()
-	defer this.openLock.Unlock()
-
-	if this.db != nil {
-		err := this.db.Close()
-
-		this.db = nil
-
-		if err != nil {
-			return err
-		}
-	}
-
-	return nil
-}
diff --git a/packages/database/interfaces.go b/packages/database/interfaces.go
index 064e311b..c17ca74b 100644
--- a/packages/database/interfaces.go
+++ b/packages/database/interfaces.go
@@ -1,11 +1,9 @@
 package database
 
 type Database interface {
-	Open() error
 	Set(key []byte, value []byte) error
 	Contains(key []byte) (bool, error)
 	Get(key []byte) ([]byte, error)
 	ForEach(func(key []byte, value []byte)) error
 	Delete(key []byte) error
-	Close() error
 }
-- 
GitLab