|  |  |  | @ -3,100 +3,127 @@ package graphvent | 
		
	
		
			
				|  |  |  |  | import ( | 
		
	
		
			
				|  |  |  |  | 	"encoding/binary" | 
		
	
		
			
				|  |  |  |  | 	"fmt" | 
		
	
		
			
				|  |  |  |  |   "reflect" | 
		
	
		
			
				|  |  |  |  | 	"reflect" | 
		
	
		
			
				|  |  |  |  |   "sync" | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | 	badger "github.com/dgraph-io/badger/v3" | 
		
	
		
			
				|  |  |  |  | ) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | const NODE_BUFFER_SIZE = 1000000 | 
		
	
		
			
				|  |  |  |  | type Database interface { | 
		
	
		
			
				|  |  |  |  |   WriteNodeInit(*Context, *Node) error | 
		
	
		
			
				|  |  |  |  |   WriteNodeChanges(*Context, *Node, map[ExtType]Changes) error | 
		
	
		
			
				|  |  |  |  |   LoadNode(*Context, NodeID) (*Node, error) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | const WRITE_BUFFER_SIZE = 1000000 | 
		
	
		
			
				|  |  |  |  | type BadgerDB struct { | 
		
	
		
			
				|  |  |  |  |   *badger.DB | 
		
	
		
			
				|  |  |  |  |   sync.Mutex | 
		
	
		
			
				|  |  |  |  |   buffer [WRITE_BUFFER_SIZE]byte | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func WriteNodeInit(ctx *Context, node *Node) error { | 
		
	
		
			
				|  |  |  |  | func (db *BadgerDB) WriteNodeInit(ctx *Context, node *Node) error { | 
		
	
		
			
				|  |  |  |  |   if node == nil { | 
		
	
		
			
				|  |  |  |  |     return fmt.Errorf("Cannot serialize nil *Node") | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   buffer := [NODE_BUFFER_SIZE]byte{} | 
		
	
		
			
				|  |  |  |  |   return db.Update(func(tx *badger.Txn) error { | 
		
	
		
			
				|  |  |  |  |     db.Lock() | 
		
	
		
			
				|  |  |  |  |     defer db.Unlock() | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return ctx.DB.Update(func(tx *badger.Txn) error { | 
		
	
		
			
				|  |  |  |  |     // Get the base key bytes
 | 
		
	
		
			
				|  |  |  |  |     id_ser, err := node.ID.MarshalBinary() | 
		
	
		
			
				|  |  |  |  |     if err != nil { | 
		
	
		
			
				|  |  |  |  |       return err | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     cur := 0 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Write Node value
 | 
		
	
		
			
				|  |  |  |  |     written, err := Serialize(ctx, node, buffer[:]) | 
		
	
		
			
				|  |  |  |  |     written, err := Serialize(ctx, node, db.buffer[cur:]) | 
		
	
		
			
				|  |  |  |  |     if err != nil { | 
		
	
		
			
				|  |  |  |  |       return err | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     err = tx.Set(id_ser, buffer[:written]) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     err = tx.Set(id_ser, db.buffer[cur:cur+written]) | 
		
	
		
			
				|  |  |  |  |     if err != nil { | 
		
	
		
			
				|  |  |  |  |       return err | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     cur += written | 
		
	
		
			
				|  |  |  |  |      | 
		
	
		
			
				|  |  |  |  |     // Write empty signal queue
 | 
		
	
		
			
				|  |  |  |  |     sigqueue_id := append(id_ser, []byte(" - SIGQUEUE")...) | 
		
	
		
			
				|  |  |  |  |     written, err = Serialize(ctx, node.SignalQueue, buffer[:]) | 
		
	
		
			
				|  |  |  |  |     written, err = Serialize(ctx, node.SignalQueue, db.buffer[cur:]) | 
		
	
		
			
				|  |  |  |  |     if err != nil { | 
		
	
		
			
				|  |  |  |  |       return err | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     err = tx.Set(sigqueue_id, buffer[:written]) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     err = tx.Set(sigqueue_id, db.buffer[cur:cur+written]) | 
		
	
		
			
				|  |  |  |  |     if err != nil { | 
		
	
		
			
				|  |  |  |  |       return err | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     cur += written | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Write node extension list
 | 
		
	
		
			
				|  |  |  |  |     ext_list := []ExtType{} | 
		
	
		
			
				|  |  |  |  |     for ext_type := range(node.Extensions) { | 
		
	
		
			
				|  |  |  |  |       ext_list = append(ext_list, ext_type) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     written, err = Serialize(ctx, ext_list, buffer[:]) | 
		
	
		
			
				|  |  |  |  |     written, err = Serialize(ctx, ext_list, db.buffer[cur:]) | 
		
	
		
			
				|  |  |  |  |     if err != nil { | 
		
	
		
			
				|  |  |  |  |       return err | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     ext_list_id := append(id_ser, []byte(" - EXTLIST")...) | 
		
	
		
			
				|  |  |  |  |     err = tx.Set(ext_list_id, buffer[:written]) | 
		
	
		
			
				|  |  |  |  |     err = tx.Set(ext_list_id, db.buffer[cur:cur+written]) | 
		
	
		
			
				|  |  |  |  |     if err != nil { | 
		
	
		
			
				|  |  |  |  |       return err | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     cur += written | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // For each extension:
 | 
		
	
		
			
				|  |  |  |  |     for ext_type, ext := range(node.Extensions) { | 
		
	
		
			
				|  |  |  |  |       // Write each extension's current value
 | 
		
	
		
			
				|  |  |  |  |       ext_id := binary.BigEndian.AppendUint64(id_ser, uint64(ext_type)) | 
		
	
		
			
				|  |  |  |  |       written, err := SerializeValue(ctx, reflect.ValueOf(ext).Elem(), buffer[:]) | 
		
	
		
			
				|  |  |  |  |       written, err := SerializeValue(ctx, reflect.ValueOf(ext).Elem(), db.buffer[cur:]) | 
		
	
		
			
				|  |  |  |  |       if err != nil { | 
		
	
		
			
				|  |  |  |  |         return err | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       err = tx.Set(ext_id, buffer[:written]) | 
		
	
		
			
				|  |  |  |  |       err = tx.Set(ext_id, db.buffer[cur:cur+written]) | 
		
	
		
			
				|  |  |  |  |       if err != nil { | 
		
	
		
			
				|  |  |  |  |         return err | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       cur += written | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return nil | 
		
	
		
			
				|  |  |  |  |   }) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func WriteNodeChanges(ctx *Context, node *Node, changes map[ExtType]Changes) error { | 
		
	
		
			
				|  |  |  |  |   buffer := [NODE_BUFFER_SIZE]byte{} | 
		
	
		
			
				|  |  |  |  | func (db *BadgerDB) WriteNodeChanges(ctx *Context, node *Node, changes map[ExtType]Changes) error { | 
		
	
		
			
				|  |  |  |  |   return db.Update(func(tx *badger.Txn) error { | 
		
	
		
			
				|  |  |  |  |     db.Lock() | 
		
	
		
			
				|  |  |  |  |     defer db.Unlock() | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return ctx.DB.Update(func(tx *badger.Txn) error { | 
		
	
		
			
				|  |  |  |  |     // Get the base key bytes
 | 
		
	
		
			
				|  |  |  |  |     id_ser, err := node.ID.MarshalBinary() | 
		
	
		
			
				|  |  |  |  |     if err != nil { | 
		
	
		
			
				|  |  |  |  |       return fmt.Errorf("Marshal ID error: %+w", err) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     id_bytes := ([16]byte)(node.ID) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     cur := 0 | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Write the signal queue if it needs to be written
 | 
		
	
		
			
				|  |  |  |  |     if node.writeSignalQueue { | 
		
	
		
			
				|  |  |  |  |       node.writeSignalQueue = false | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       sigqueue_id := append(id_ser, []byte(" - SIGQUEUE")...) | 
		
	
		
			
				|  |  |  |  |       written, err := Serialize(ctx, node.SignalQueue, buffer[:]) | 
		
	
		
			
				|  |  |  |  |       sigqueue_id := append(id_bytes[:], []byte(" - SIGQUEUE")...) | 
		
	
		
			
				|  |  |  |  |       written, err := Serialize(ctx, node.SignalQueue, db.buffer[cur:]) | 
		
	
		
			
				|  |  |  |  |       if err != nil { | 
		
	
		
			
				|  |  |  |  |         return fmt.Errorf("SignalQueue Serialize Error: %+v, %w", node.SignalQueue, err) | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       err = tx.Set(sigqueue_id, buffer[:written]) | 
		
	
		
			
				|  |  |  |  |       err = tx.Set(sigqueue_id, db.buffer[cur:cur+written]) | 
		
	
		
			
				|  |  |  |  |       if err != nil { | 
		
	
		
			
				|  |  |  |  |         return fmt.Errorf("SignalQueue set error: %+v, %w", node.SignalQueue, err) | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       cur += written | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // For each ext in changes
 | 
		
	
	
		
			
				
					|  |  |  | @ -106,24 +133,26 @@ func WriteNodeChanges(ctx *Context, node *Node, changes map[ExtType]Changes) err | 
		
	
		
			
				|  |  |  |  |       if exists == false { | 
		
	
		
			
				|  |  |  |  |         return fmt.Errorf("%s is not an extension in %s", ext_type, node.ID) | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       ext_id := binary.BigEndian.AppendUint64(id_ser, uint64(ext_type)) | 
		
	
		
			
				|  |  |  |  |       written, err := SerializeValue(ctx, reflect.ValueOf(ext).Elem(), buffer[:]) | 
		
	
		
			
				|  |  |  |  |       ext_id := binary.BigEndian.AppendUint64(id_bytes[:], uint64(ext_type)) | 
		
	
		
			
				|  |  |  |  |       written, err := SerializeValue(ctx, reflect.ValueOf(ext).Elem(), db.buffer[cur:]) | 
		
	
		
			
				|  |  |  |  |       if err != nil { | 
		
	
		
			
				|  |  |  |  |         return fmt.Errorf("Extension serialize err: %s, %w", reflect.TypeOf(ext), err) | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |       err = tx.Set(ext_id, buffer[:written]) | 
		
	
		
			
				|  |  |  |  |       err = tx.Set(ext_id, db.buffer[cur:cur+written]) | 
		
	
		
			
				|  |  |  |  |       if err != nil { | 
		
	
		
			
				|  |  |  |  |         return fmt.Errorf("Extension set err: %s, %w", reflect.TypeOf(ext), err) | 
		
	
		
			
				|  |  |  |  |       } | 
		
	
		
			
				|  |  |  |  |       cur += written | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  |     return nil | 
		
	
		
			
				|  |  |  |  |   }) | 
		
	
		
			
				|  |  |  |  | } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  | func LoadNode(ctx *Context, id NodeID) (*Node, error) { | 
		
	
		
			
				|  |  |  |  | func (db *BadgerDB) LoadNode(ctx *Context, id NodeID) (*Node, error) { | 
		
	
		
			
				|  |  |  |  |   var node *Node = nil | 
		
	
		
			
				|  |  |  |  |   err := ctx.DB.View(func(tx *badger.Txn) error { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   err := db.View(func(tx *badger.Txn) error { | 
		
	
		
			
				|  |  |  |  |     // Get the base key bytes
 | 
		
	
		
			
				|  |  |  |  |     id_ser, err := id.MarshalBinary() | 
		
	
		
			
				|  |  |  |  |     if err != nil { | 
		
	
	
		
			
				
					|  |  |  | @ -137,12 +166,13 @@ func LoadNode(ctx *Context, id NodeID) (*Node, error) { | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     err = node_item.Value(func(val []byte) error { | 
		
	
		
			
				|  |  |  |  |       ctx.Log.Logf("db", "DESERIALIZE_NODE(%d bytes): %+v", len(val), val) | 
		
	
		
			
				|  |  |  |  |       node, err = Deserialize[*Node](ctx, val) | 
		
	
		
			
				|  |  |  |  |       return err | 
		
	
		
			
				|  |  |  |  |     }) | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     if err != nil { | 
		
	
		
			
				|  |  |  |  |       return nil | 
		
	
		
			
				|  |  |  |  |       return fmt.Errorf("Failed to deserialize Node %s - %w", id, err) | 
		
	
		
			
				|  |  |  |  |     } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |     // Get the signal queue
 | 
		
	
	
		
			
				
					|  |  |  | @ -211,6 +241,8 @@ func LoadNode(ctx *Context, id NodeID) (*Node, error) { | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   if err != nil { | 
		
	
		
			
				|  |  |  |  |     return nil, err | 
		
	
		
			
				|  |  |  |  |   } else if node == nil { | 
		
	
		
			
				|  |  |  |  |     return nil, fmt.Errorf("Tried to return nil *Node from BadgerDB.LoadNode without error") | 
		
	
		
			
				|  |  |  |  |   } | 
		
	
		
			
				|  |  |  |  | 
 | 
		
	
		
			
				|  |  |  |  |   return node, nil | 
		
	
	
		
			
				
					|  |  |  | 
 |