ceremonyclient/node/store/hypergraph.go

239 lines
5.7 KiB
Go

package store
import (
"github.com/pkg/errors"
"go.uber.org/zap"
"source.quilibrium.com/quilibrium/monorepo/node/hypergraph/application"
)
type HypergraphStore interface {
NewTransaction(indexed bool) (Transaction, error)
LoadHypergraph() (
*application.Hypergraph,
error,
)
SaveHypergraph(
txn Transaction,
hg *application.Hypergraph,
) error
}
var _ HypergraphStore = (*PebbleHypergraphStore)(nil)
type PebbleHypergraphStore struct {
db KVDB
logger *zap.Logger
}
func NewPebbleHypergraphStore(
db KVDB,
logger *zap.Logger,
) *PebbleHypergraphStore {
return &PebbleHypergraphStore{
db,
logger,
}
}
const (
HYPERGRAPH_SHARD = 0x09
VERTEX_ADDS = 0x00
VERTEX_REMOVES = 0x10
HYPEREDGE_ADDS = 0x01
HYPEREDGE_REMOVES = 0x11
)
func hypergraphVertexAddsKey(shardKey application.ShardKey) []byte {
key := []byte{HYPERGRAPH_SHARD, VERTEX_ADDS}
key = append(key, shardKey.L1[:]...)
key = append(key, shardKey.L2[:]...)
return key
}
func hypergraphVertexRemovesKey(shardKey application.ShardKey) []byte {
key := []byte{HYPERGRAPH_SHARD, VERTEX_REMOVES}
key = append(key, shardKey.L1[:]...)
key = append(key, shardKey.L2[:]...)
return key
}
func hypergraphHyperedgeAddsKey(shardKey application.ShardKey) []byte {
key := []byte{HYPERGRAPH_SHARD, HYPEREDGE_ADDS}
key = append(key, shardKey.L1[:]...)
key = append(key, shardKey.L2[:]...)
return key
}
func hypergraphHyperedgeRemovesKey(shardKey application.ShardKey) []byte {
key := []byte{HYPERGRAPH_SHARD, HYPEREDGE_REMOVES}
key = append(key, shardKey.L1[:]...)
key = append(key, shardKey.L2[:]...)
return key
}
func shardKeyFromKey(key []byte) application.ShardKey {
return application.ShardKey{
L1: [3]byte(key[2:5]),
L2: [32]byte(key[5:]),
}
}
func (p *PebbleHypergraphStore) NewTransaction(indexed bool) (
Transaction,
error,
) {
return p.db.NewBatch(indexed), nil
}
func (p *PebbleHypergraphStore) LoadHypergraph() (
*application.Hypergraph,
error,
) {
hg := application.NewHypergraph()
vertexAddsIter, err := p.db.NewIter(
[]byte{HYPERGRAPH_SHARD, VERTEX_ADDS},
[]byte{HYPERGRAPH_SHARD, VERTEX_REMOVES},
)
if err != nil {
return nil, errors.Wrap(err, "load hypergraph")
}
defer vertexAddsIter.Close()
for vertexAddsIter.First(); vertexAddsIter.Valid(); vertexAddsIter.Next() {
shardKey := make([]byte, len(vertexAddsIter.Key()))
copy(shardKey, vertexAddsIter.Key())
err := hg.ImportFromBytes(
application.VertexAtomType,
application.AddsPhaseType,
shardKeyFromKey(shardKey),
vertexAddsIter.Value(),
)
if err != nil {
return nil, errors.Wrap(err, "load hypergraph")
}
}
vertexRemovesIter, err := p.db.NewIter(
[]byte{HYPERGRAPH_SHARD, VERTEX_REMOVES},
[]byte{HYPERGRAPH_SHARD, VERTEX_REMOVES + 1},
)
if err != nil {
return nil, errors.Wrap(err, "load hypergraph")
}
defer vertexRemovesIter.Close()
for vertexRemovesIter.First(); vertexRemovesIter.Valid(); vertexRemovesIter.Next() {
shardKey := make([]byte, len(vertexRemovesIter.Key()))
copy(shardKey, vertexRemovesIter.Key())
err := hg.ImportFromBytes(
application.VertexAtomType,
application.RemovesPhaseType,
shardKeyFromKey(shardKey),
vertexRemovesIter.Value(),
)
if err != nil {
return nil, errors.Wrap(err, "load hypergraph")
}
}
hyperedgeAddsIter, err := p.db.NewIter(
[]byte{HYPERGRAPH_SHARD, HYPEREDGE_ADDS},
[]byte{HYPERGRAPH_SHARD, HYPEREDGE_REMOVES},
)
if err != nil {
return nil, errors.Wrap(err, "load hypergraph")
}
defer hyperedgeAddsIter.Close()
for hyperedgeAddsIter.First(); hyperedgeAddsIter.Valid(); hyperedgeAddsIter.Next() {
shardKey := make([]byte, len(hyperedgeAddsIter.Key()))
copy(shardKey, hyperedgeAddsIter.Key())
err := hg.ImportFromBytes(
application.HyperedgeAtomType,
application.AddsPhaseType,
shardKeyFromKey(shardKey),
hyperedgeAddsIter.Value(),
)
if err != nil {
return nil, errors.Wrap(err, "load hypergraph")
}
}
hyperedgeRemovesIter, err := p.db.NewIter(
[]byte{HYPERGRAPH_SHARD, HYPEREDGE_REMOVES},
[]byte{HYPERGRAPH_SHARD, HYPEREDGE_REMOVES + 1},
)
if err != nil {
return nil, errors.Wrap(err, "load hypergraph")
}
defer hyperedgeRemovesIter.Close()
for hyperedgeRemovesIter.First(); hyperedgeRemovesIter.Valid(); hyperedgeRemovesIter.Next() {
shardKey := make([]byte, len(hyperedgeRemovesIter.Key()))
copy(shardKey, hyperedgeRemovesIter.Key())
err := hg.ImportFromBytes(
application.HyperedgeAtomType,
application.RemovesPhaseType,
shardKeyFromKey(shardKey),
hyperedgeRemovesIter.Value(),
)
if err != nil {
return nil, errors.Wrap(err, "load hypergraph")
}
}
return hg, nil
}
func (p *PebbleHypergraphStore) SaveHypergraph(
txn Transaction,
hg *application.Hypergraph,
) error {
for shardKey, vertexAdds := range hg.GetVertexAdds() {
if vertexAdds.IsDirty() {
err := txn.Set(hypergraphVertexAddsKey(shardKey), vertexAdds.ToBytes())
if err != nil {
return errors.Wrap(err, "save hypergraph")
}
}
}
for shardKey, vertexRemoves := range hg.GetVertexRemoves() {
if vertexRemoves.IsDirty() {
err := txn.Set(
hypergraphVertexRemovesKey(shardKey),
vertexRemoves.ToBytes(),
)
if err != nil {
return errors.Wrap(err, "save hypergraph")
}
}
}
for shardKey, hyperedgeAdds := range hg.GetHyperedgeAdds() {
if hyperedgeAdds.IsDirty() {
err := txn.Set(
hypergraphHyperedgeAddsKey(shardKey),
hyperedgeAdds.ToBytes(),
)
if err != nil {
return errors.Wrap(err, "save hypergraph")
}
}
}
for shardKey, hyperedgeRemoves := range hg.GetHyperedgeRemoves() {
if hyperedgeRemoves.IsDirty() {
err := txn.Set(
hypergraphHyperedgeRemovesKey(shardKey),
hyperedgeRemoves.ToBytes(),
)
if err != nil {
return errors.Wrap(err, "save hypergraph")
}
}
}
return nil
}