diff --git a/docs/fabric/fabricdev/core/fabricdev/vault/version.go b/docs/fabric/fabricdev/core/fabricdev/vault/version.go index 8db8121bf..253d2e55c 100644 --- a/docs/fabric/fabricdev/core/fabricdev/vault/version.go +++ b/docs/fabric/fabricdev/core/fabricdev/vault/version.go @@ -17,8 +17,8 @@ import ( type CounterBasedVersionBuilder struct{} -func (c *CounterBasedVersionBuilder) VersionedValues(rws *vault.ReadWriteSet, ns driver.Namespace, writes vault.NamespaceWrites, block driver.BlockNum, indexInBloc driver.TxNum) (map[driver.PKey]vault.VersionedValue, error) { - vals := make(map[driver.PKey]vault.VersionedValue, len(writes)) +func (c *CounterBasedVersionBuilder) VersionedValues(rws *vault.ReadWriteSet, ns driver.Namespace, writes vault.NamespaceWrites, block driver.BlockNum, indexInBloc driver.TxNum) (map[driver.PKey]driver.VaultValue, error) { + vals := make(map[driver.PKey]driver.VaultValue, len(writes)) reads := rws.Reads[ns] for pkey, val := range writes { @@ -26,7 +26,7 @@ func (c *CounterBasedVersionBuilder) VersionedValues(rws *vault.ReadWriteSet, ns if err != nil { return nil, err } - vals[pkey] = vault.VersionedValue{Raw: val, Version: v} + vals[pkey] = driver.VaultValue{Raw: val, Version: v} } return vals, nil } @@ -48,8 +48,8 @@ func version(reads vault.NamespaceReads, pkey driver.PKey) (vault.Version, error return Marshal(counter + 1), nil } -func (c *CounterBasedVersionBuilder) VersionedMetaValues(rws *vault.ReadWriteSet, ns driver.Namespace, writes vault.KeyedMetaWrites, block driver.BlockNum, indexInBloc driver.TxNum) (map[driver.PKey]driver.VersionedMetadataValue, error) { - vals := make(map[driver.PKey]driver.VersionedMetadataValue, len(writes)) +func (c *CounterBasedVersionBuilder) VersionedMetaValues(rws *vault.ReadWriteSet, ns driver.Namespace, writes vault.KeyedMetaWrites, block driver.BlockNum, indexInBloc driver.TxNum) (map[driver.PKey]driver.VaultMetadataValue, error) { + vals := make(map[driver.PKey]driver.VaultMetadataValue, len(writes)) reads := rws.Reads[ns] for pkey, val := range writes { @@ -58,7 +58,7 @@ func (c *CounterBasedVersionBuilder) VersionedMetaValues(rws *vault.ReadWriteSet return nil, err } - vals[pkey] = driver.VersionedMetadataValue{Metadata: val, Version: v} + vals[pkey] = driver.VaultMetadataValue{Metadata: val, Version: v} } return vals, nil } diff --git a/integration/fabric/iou/views/utils.go b/integration/fabric/iou/views/utils.go index dc80ac4ea..0c089e941 100644 --- a/integration/fabric/iou/views/utils.go +++ b/integration/fabric/iou/views/utils.go @@ -13,22 +13,22 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" - "github.com/hyperledger-labs/fabric-smart-client/platform/fabric" + fdriver "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver" ) var logger = logging.MustGetLogger("fabric.iou") type FinalityListener struct { ExpectedTxID string - ExpectedVC fabric.ValidationCode + ExpectedVC fdriver.ValidationCode WaitGroup *sync.WaitGroup } -func NewFinalityListener(expectedTxID string, expectedVC fabric.ValidationCode, waitGroup *sync.WaitGroup) *FinalityListener { +func NewFinalityListener(expectedTxID string, expectedVC fdriver.ValidationCode, waitGroup *sync.WaitGroup) *FinalityListener { return &FinalityListener{ExpectedTxID: expectedTxID, ExpectedVC: expectedVC, WaitGroup: waitGroup} } -func (t *FinalityListener) OnStatus(_ context.Context, txID driver.TxID, vc fabric.ValidationCode, _ string) { +func (t *FinalityListener) OnStatus(_ context.Context, txID driver.TxID, vc fdriver.ValidationCode, _ string) { logger.Infof("on status [%s][%d]", txID, vc) if txID == t.ExpectedTxID && vc == t.ExpectedVC { time.Sleep(5 * time.Second) diff --git a/integration/nwo/fabric/network/network_support.go b/integration/nwo/fabric/network/network_support.go index 8212fbae3..a5fafe8b8 100755 --- a/integration/nwo/fabric/network/network_support.go +++ b/integration/nwo/fabric/network/network_support.go @@ -1468,8 +1468,12 @@ func (n *Network) nextColor() string { return fmt.Sprintf("%dm", color) } -func (n *Network) FSCNodeVaultDir(uniqueName string) string { - return filepath.Join(n.Context.RootDir(), "fsc", "nodes", uniqueName, n.Prefix, "vault") +func (n *Network) FSCNodeStorages(uniqueName string) string { + return filepath.Join(n.Context.RootDir(), "fsc", "nodes", uniqueName, n.Prefix) +} + +func (n *Network) FSCNodeStorageDir(uniqueName string, suffix string) string { + return filepath.Join(n.FSCNodeStorages(uniqueName), suffix) } func (n *Network) OrdererBootstrapFile() string { @@ -1615,7 +1619,7 @@ func (n *Network) GenerateCoreConfig(p *topology.Peer) { "PeerAddress": func(o *topology.Peer, portName api.PortName) string { return n.PeerAddress(o, portName) }, "CACertsBundlePath": func() string { return n.CACertsBundlePath() }, "VaultOpts": func() node.PersistenceOpts { - return fsc.PersistenceOpts(VaultPersistencePrefix, p.FSCNode.Options) + return fsc.PersistenceOpts(VaultPersistencePrefix, p.FSCNode.Options, n.FSCNodeStorageDir(uniqueName, "vault")) }, "FabricName": func() string { return n.topology.Name() }, "DefaultNetwork": func() bool { return defaultNetwork }, diff --git a/integration/nwo/fabric/platform.go b/integration/nwo/fabric/platform.go index eccd12319..462738fc8 100644 --- a/integration/nwo/fabric/platform.go +++ b/integration/nwo/fabric/platform.go @@ -188,7 +188,7 @@ func (p *Platform) DeleteVault(id string) { fscPeer := p.Network.FSCPeerByName(id) Expect(fscPeer).ToNot(BeNil()) for _, uniqueName := range fscPeer.FSCNode.ReplicaUniqueNames() { - Expect(os.RemoveAll(p.Network.FSCNodeVaultDir(uniqueName))).ToNot(HaveOccurred()) + Expect(os.RemoveAll(p.Network.FSCNodeStorageDir(uniqueName, "vault"))).ToNot(HaveOccurred()) } } diff --git a/integration/nwo/fsc/fsc.go b/integration/nwo/fsc/fsc.go index 7720fcfa5..d820218ba 100755 --- a/integration/nwo/fsc/fsc.go +++ b/integration/nwo/fsc/fsc.go @@ -37,7 +37,6 @@ import ( view2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/client/view/cmd" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/client/web" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/crypto" - mem "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/memory" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/postgres" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/grpc" @@ -519,25 +518,25 @@ func (p *Platform) GenerateCoreConfig(peer *node2.Replica) { "ToLower": func(s string) string { return strings.ToLower(s) }, "ReplaceAll": func(s, old, new string) string { return strings.Replace(s, old, new, -1) }, "KVSOpts": func() node2.PersistenceOpts { - return PersistenceOpts(KvsPersistencePrefix, peer.Options) + return PersistenceOpts(KvsPersistencePrefix, peer.Options, p.NodeStorageDir(peer.UniqueName, "kvs")) }, "BindingOpts": func() node2.PersistenceOpts { - return PersistenceOpts(BindingPersistencePrefix, peer.Options) + return PersistenceOpts(BindingPersistencePrefix, peer.Options, p.NodeStorageDir(peer.UniqueName, "bind")) }, "SignerInfoOpts": func() node2.PersistenceOpts { - return PersistenceOpts(SignerInfoPersistencePrefix, peer.Options) + return PersistenceOpts(SignerInfoPersistencePrefix, peer.Options, p.NodeStorageDir(peer.UniqueName, "sig")) }, "AuditInfoOpts": func() node2.PersistenceOpts { - return PersistenceOpts(AuditInfoPersistencePrefix, peer.Options) + return PersistenceOpts(AuditInfoPersistencePrefix, peer.Options, p.NodeStorageDir(peer.UniqueName, "aud")) }, "EndorseTxOpts": func() node2.PersistenceOpts { - return PersistenceOpts(EndorseTxPersistencePrefix, peer.Options) + return PersistenceOpts(EndorseTxPersistencePrefix, peer.Options, p.NodeStorageDir(peer.UniqueName, "etx")) }, "EnvelopeOpts": func() node2.PersistenceOpts { - return PersistenceOpts(EnvelopePersistencePrefix, peer.Options) + return PersistenceOpts(EnvelopePersistencePrefix, peer.Options, p.NodeStorageDir(peer.UniqueName, "env")) }, "MetadataOpts": func() node2.PersistenceOpts { - return PersistenceOpts(MetadataPersistencePrefix, peer.Options) + return PersistenceOpts(MetadataPersistencePrefix, peer.Options, p.NodeStorageDir(peer.UniqueName, "mtd")) }, "Resolvers": func() []*Resolver { return resolvers }, "WebEnabled": func() bool { return p.Topology.WebEnabled }, @@ -552,14 +551,20 @@ func (p *Platform) GenerateCoreConfig(peer *node2.Replica) { } -func PersistenceOpts(prefix string, o *node2.Options) node2.PersistenceOpts { +func PersistenceOpts(prefix string, o *node2.Options, dir string) node2.PersistenceOpts { if sqlOpts := o.GetPersistence(prefix); sqlOpts != nil { return node2.PersistenceOpts{ Type: sql.SQLPersistence, SQL: sqlOpts, } } - return node2.PersistenceOpts{Type: mem.MemoryPersistence} + return node2.PersistenceOpts{ + Type: sql.SQLPersistence, + SQL: &node2.SQLOpts{ + DriverType: sql.SQLite, + DataSource: fmt.Sprintf("%s.sqlite", dir), + CreateSchema: true, + }} } func (p *Platform) BootstrapViewNodeGroupRunner() ifrit.Runner { @@ -668,8 +673,12 @@ func (p *Platform) NodeClientConfigPath(peer *node2.Replica) string { return filepath.Join(p.Context.RootDir(), "fsc", "nodes", peer.UniqueName, "client-config.yaml") } +func (p *Platform) NodeStorages(uniqueName string) string { + return filepath.Join(p.Context.RootDir(), "fsc", "nodes", uniqueName) +} + func (p *Platform) NodeStorageDir(uniqueName string, dirName string) string { - return filepath.Join(p.Context.RootDir(), "fsc", "nodes", uniqueName, dirName) + return filepath.Join(p.NodeStorages(uniqueName), dirName) } func (p *Platform) NodeConfigPath(peer *node2.Replica) string { diff --git a/platform/common/core/generic/vault/helpers.go b/platform/common/core/generic/vault/helpers.go index 1c9f4c5d1..7eaae8caf 100644 --- a/platform/common/core/generic/vault/helpers.go +++ b/platform/common/core/generic/vault/helpers.go @@ -31,7 +31,7 @@ const ( unknown ) -var RemoveNils func(items []VersionedRead) []VersionedRead +var RemoveNils func(items []driver.VaultRead) []driver.VaultRead var VCProvider = driver.NewValidationCodeProvider(map[ValidationCode]driver.TxStatusCode{ valid: driver.Valid, @@ -129,7 +129,7 @@ func TTestInterceptorConcurrency(t *testing.T, ddb driver2.VaultPersistence, vp assert.Nil(t, v) err = ddb.Store(context.Background(), nil, driver.Writes{ - ns: map[driver.PKey]driver.VersionedValue{ + ns: map[driver.PKey]driver.VaultValue{ k: {Raw: []byte("val"), Version: versionBlockTxNumToBytes(35, 1)}, }, }, nil) @@ -146,7 +146,7 @@ func TTestInterceptorConcurrency(t *testing.T, ddb driver2.VaultPersistence, vp assert.Nil(t, mv) err = ddb.Store(context.Background(), nil, nil, driver.MetaWrites{ - ns: map[driver.PKey]driver.VersionedMetadataValue{ + ns: map[driver.PKey]driver.VaultMetadataValue{ mk: { Version: versionBlockTxNumToBytes(36, 1), Metadata: map[string][]byte{"k": []byte("v")}, @@ -256,7 +256,7 @@ func TTestQueryExecutor(t *testing.T, ddb driver2.VaultPersistence, vp artifacts assert.NoError(t, err) err = ddb.Store(context.Background(), nil, driver.Writes{ - ns: map[driver.PKey]driver.VersionedValue{ + ns: map[driver.PKey]driver.VaultValue{ "k2": {Raw: []byte("k2_value"), Version: versionBlockTxNumToBytes(35, 1)}, "k3": {Raw: []byte("k3_value"), Version: versionBlockTxNumToBytes(35, 2)}, "k1": {Raw: []byte("k1_value"), Version: versionBlockTxNumToBytes(35, 3)}, @@ -281,7 +281,7 @@ func TTestQueryExecutor(t *testing.T, ddb driver2.VaultPersistence, vp artifacts res, err := collections.ReadAll(itr) assert.NoError(t, err) assert.Len(t, res, 4) - assert.ElementsMatch(t, []VersionedRead{ + assert.ElementsMatch(t, []driver.VaultRead{ {Key: "k1", Raw: []byte("k1_value"), Version: versionBlockTxNumToBytes(35, 3)}, {Key: "k111", Raw: []byte("k111_value"), Version: versionBlockTxNumToBytes(35, 4)}, {Key: "k2", Raw: []byte("k2_value"), Version: versionBlockTxNumToBytes(35, 1)}, @@ -293,7 +293,7 @@ func TTestQueryExecutor(t *testing.T, ddb driver2.VaultPersistence, vp artifacts res, err = collections.ReadAll(itr) assert.NoError(t, err) assert.Len(t, res, 3) - assert.Equal(t, []VersionedRead{ + assert.Equal(t, []driver.VaultRead{ {Key: "k1", Raw: []byte("k1_value"), Version: versionBlockTxNumToBytes(35, 3)}, {Key: "k111", Raw: []byte("k111_value"), Version: versionBlockTxNumToBytes(35, 4)}, {Key: "k2", Raw: []byte("k2_value"), Version: versionBlockTxNumToBytes(35, 1)}, @@ -304,7 +304,7 @@ func TTestQueryExecutor(t *testing.T, ddb driver2.VaultPersistence, vp artifacts res, err = collections.ReadAll(itr) assert.NoError(t, err) assert.Len(t, res, 3) - assert.ElementsMatch(t, []VersionedRead{ + assert.ElementsMatch(t, []driver.VaultRead{ {Key: "k1", Raw: []byte("k1_value"), Version: versionBlockTxNumToBytes(35, 3)}, {Key: "k2", Raw: []byte("k2_value"), Version: versionBlockTxNumToBytes(35, 1)}, {Key: "k111", Raw: []byte("k111_value"), Version: versionBlockTxNumToBytes(35, 4)}, @@ -314,7 +314,7 @@ func TTestQueryExecutor(t *testing.T, ddb driver2.VaultPersistence, vp artifacts assert.NoError(t, err) res, err = collections.ReadAll(itr) assert.NoError(t, err) - var expected = RemoveNils([]VersionedRead{ + var expected = RemoveNils([]driver.VaultRead{ {Key: "k1", Raw: []byte("k1_value"), Version: versionBlockTxNumToBytes(35, 3)}, }) assert.Equal(t, expected, res) @@ -327,7 +327,7 @@ func TTestShardLikeCommit(t *testing.T, ddb driver2.VaultPersistence, vp artifac // Populate the DB with some data at some height err := ddb.Store(context.Background(), nil, driver.Writes{ - ns: map[driver.PKey]driver.VersionedValue{ + ns: map[driver.PKey]driver.VaultValue{ k1: {Raw: []byte("k1val"), Version: versionBlockTxNumToBytes(35, 1)}, k2: {Raw: []byte("k2val"), Version: versionBlockTxNumToBytes(37, 3)}, }, @@ -433,11 +433,11 @@ func TTestShardLikeCommit(t *testing.T, ddb driver2.VaultPersistence, vp artifac // check the content of the kvs after that vv, err := ddb.GetState(context.Background(), ns, k1) assert.NoError(t, err) - assert.Equal(t, &VersionedRead{Key: "key1", Raw: []byte("k1FromTxidValid"), Version: versionBlockTxNumToBytes(38, 10)}, vv) + assert.Equal(t, &driver.VaultRead{Key: "key1", Raw: []byte("k1FromTxidValid"), Version: versionBlockTxNumToBytes(38, 10)}, vv) vv, err = ddb.GetState(context.Background(), ns, k2) assert.NoError(t, err) - assert.Equal(t, &VersionedRead{Key: "key2", Raw: []byte("k2FromTxidValid"), Version: versionBlockTxNumToBytes(38, 10)}, vv) + assert.Equal(t, &driver.VaultRead{Key: "key2", Raw: []byte("k2FromTxidValid"), Version: versionBlockTxNumToBytes(38, 10)}, vv) // all interceptors should be gone assert.Len(t, aVault.interceptors, 0) @@ -503,7 +503,7 @@ func TTestMerge(t *testing.T, ddb driver2.VaultPersistence, vp artifactsProvider vault2, err := vp.NewNonCachedVault(ddb) assert.NoError(t, err) err = ddb.Store(context.Background(), nil, driver.Writes{ - ns: map[driver.PKey]driver.VersionedValue{ + ns: map[driver.PKey]driver.VaultValue{ k1: {Raw: []byte("v1"), Version: versionBlockTxNumToBytes(35, 1)}, }, }, nil) @@ -626,7 +626,7 @@ func TTestInspector(t *testing.T, ddb driver2.VaultPersistence, vp artifactsProv aVault, err := vp.NewNonCachedVault(ddb) assert.NoError(t, err) err = ddb.Store(context.Background(), nil, driver.Writes{ - ns: map[driver.PKey]driver.VersionedValue{ + ns: map[driver.PKey]driver.VaultValue{ k1: {Raw: []byte("v1"), Version: versionBlockTxNumToBytes(35, 1)}, }, }, nil) @@ -693,12 +693,12 @@ func TTestRun(t *testing.T, db1, db2 driver2.VaultPersistence, vp artifactsProvi // create and populate 2 DBs err := db1.Store(context.Background(), nil, driver.Writes{ - ns: map[driver.PKey]driver.VersionedValue{ + ns: map[driver.PKey]driver.VaultValue{ k1: {Raw: []byte("v1"), Version: versionBlockTxNumToBytes(35, 1)}, }, }, driver.MetaWrites{ - ns: map[driver.PKey]driver.VersionedMetadataValue{ + ns: map[driver.PKey]driver.VaultMetadataValue{ k1Meta: {Metadata: map[string][]byte{"metakey": []byte("metavalue")}}, }, }) @@ -706,12 +706,12 @@ func TTestRun(t *testing.T, db1, db2 driver2.VaultPersistence, vp artifactsProvi err = db2.Store(context.Background(), nil, driver.Writes{ - ns: map[driver.PKey]driver.VersionedValue{ + ns: map[driver.PKey]driver.VaultValue{ k1: {Raw: []byte("v1"), Version: versionBlockTxNumToBytes(35, 1)}, }, }, driver.MetaWrites{ - ns: map[driver.PKey]driver.VersionedMetadataValue{ + ns: map[driver.PKey]driver.VaultMetadataValue{ k1Meta: {Metadata: map[string][]byte{"metakey": []byte("metavalue")}}, }, }) @@ -1061,7 +1061,7 @@ func TTestRun(t *testing.T, db1, db2 driver2.VaultPersistence, vp artifactsProvi assert.NoError(t, err) vv2, err = db2.GetState(context.Background(), ns, k2) assert.NoError(t, err) - assert.Equal(t, &VersionedRead{Key: "key2", Raw: []byte("v2_updated"), Version: versionBlockTxNumToBytes(35, 2)}, vv1) + assert.Equal(t, &driver.VaultRead{Key: "key2", Raw: []byte("v2_updated"), Version: versionBlockTxNumToBytes(35, 2)}, vv1) assert.Equal(t, vv1, vv2) meta1, ver1, err := db1.GetStateMetadata(context.Background(), ns, k1Meta) @@ -1098,7 +1098,7 @@ func compare(t *testing.T, ns string, db1, db2 driver2.VaultPersistence) { assert.Equal(t, res1, res2) } -func byKey(a, b VersionedRead) int { return strings.Compare(a.Key, b.Key) } +func byKey(a, b driver.VaultRead) int { return strings.Compare(a.Key, b.Key) } // //func queryVault(v *Vault[Code], ns driver.Namespace, key driver.PKey, mkey driver.MKey) (driver.RawValue, driver.Metadata, driver.TxNum, driver.BlockNum, error) { @@ -1128,19 +1128,19 @@ func byKey(a, b VersionedRead) int { return strings.Compare(a.Key, b.Key) } // key string //} // -//func (db *deadlockErrorPersistence) GetState(namespace driver.Namespace, key driver.PKey) (VersionedValue, error) { +//func (db *deadlockErrorPersistence) GetState(namespace driver.Namespace, key driver.PKey) (VaultValue, error) { // return db.VersionedPersistence.GetState(namespace, key) //} // -//func (db *deadlockErrorPersistence) GetStateRangeScanIterator(namespace driver.Namespace, startKey, endKey driver.PKey) (collections.Iterator[*VersionedRead], error) { +//func (db *deadlockErrorPersistence) GetStateRangeScanIterator(namespace driver.Namespace, startKey, endKey driver.PKey) (collections.Iterator[*driver.VaultRead], error) { // return db.VersionedPersistence.GetStateRangeScanIterator(namespace, startKey, endKey) //} // -//func (db *deadlockErrorPersistence) GetStateSetIterator(ns driver.Namespace, keys ...driver.PKey) (collections.Iterator[*VersionedRead], error) { +//func (db *deadlockErrorPersistence) GetStateSetIterator(ns driver.Namespace, keys ...driver.PKey) (collections.Iterator[*driver.VaultRead], error) { // return db.VersionedPersistence.GetStateSetIterator(ns, keys...) //} // -//func (db *deadlockErrorPersistence) SetState(namespace driver.Namespace, key driver.PKey, value VersionedValue) error { +//func (db *deadlockErrorPersistence) SetState(namespace driver.Namespace, key driver.PKey, value VaultValue) error { // if key == db.key && db.failures > 0 { // db.failures-- // return DeadlockDetected @@ -1148,7 +1148,7 @@ func byKey(a, b VersionedRead) int { return strings.Compare(a.Key, b.Key) } // return db.VersionedPersistence.SetState(namespace, key, value) //} // -//func (db *deadlockErrorPersistence) SetStates(namespace driver.Namespace, kvs map[driver.PKey]VersionedValue) map[driver.PKey]error { +//func (db *deadlockErrorPersistence) SetStates(namespace driver.Namespace, kvs map[driver.PKey]VaultValue) map[driver.PKey]error { // errs := make(map[driver.PKey]error) // for k, v := range kvs { // if err := db.SetState(namespace, k, v); err != nil { @@ -1172,11 +1172,11 @@ func byKey(a, b VersionedRead) int { return strings.Compare(a.Key, b.Key) } // VersionedPersistence //} // -//func (db *duplicateErrorPersistence) SetState(driver.Namespace, driver.PKey, VersionedValue) error { +//func (db *duplicateErrorPersistence) SetState(driver.Namespace, driver.PKey, VaultValue) error { // return UniqueKeyViolation //} // -//func (db *duplicateErrorPersistence) SetStates(_ driver.Namespace, kvs map[driver.PKey]VersionedValue) map[driver.PKey]error { +//func (db *duplicateErrorPersistence) SetStates(_ driver.Namespace, kvs map[driver.PKey]VaultValue) map[driver.PKey]error { // errs := make(map[driver.PKey]error, len(kvs)) // for k := range kvs { // errs[k] = UniqueKeyViolation @@ -1194,15 +1194,15 @@ func byKey(a, b VersionedRead) int { return strings.Compare(a.Key, b.Key) } // return errs //} // -//func (db *duplicateErrorPersistence) GetState(namespace driver.Namespace, key driver.PKey) (VersionedValue, error) { +//func (db *duplicateErrorPersistence) GetState(namespace driver.Namespace, key driver.PKey) (VaultValue, error) { // return db.VersionedPersistence.GetState(namespace, key) //} // -//func (db *duplicateErrorPersistence) GetStateRangeScanIterator(namespace driver.Namespace, startKey, endKey driver.PKey) (collections.Iterator[*VersionedRead], error) { +//func (db *duplicateErrorPersistence) GetStateRangeScanIterator(namespace driver.Namespace, startKey, endKey driver.PKey) (collections.Iterator[*driver.VaultRead], error) { // return db.VersionedPersistence.GetStateRangeScanIterator(namespace, startKey, endKey) //} // -//func (db *duplicateErrorPersistence) GetStateSetIterator(ns driver.Namespace, keys ...driver.PKey) (collections.Iterator[*VersionedRead], error) { +//func (db *duplicateErrorPersistence) GetStateSetIterator(ns driver.Namespace, keys ...driver.PKey) (collections.Iterator[*driver.VaultRead], error) { // return db.VersionedPersistence.GetStateSetIterator(ns, keys...) //} diff --git a/platform/common/core/generic/vault/inspector.go b/platform/common/core/generic/vault/inspector.go index 20e907d14..557b236bb 100644 --- a/platform/common/core/generic/vault/inspector.go +++ b/platform/common/core/generic/vault/inspector.go @@ -51,7 +51,7 @@ func (i *Inspector) SetStateMetadata(driver.Namespace, driver.PKey, driver.Metad panic("programming error: the rwset inspector is read-only") } -func (i *Inspector) SetStateMetadatas(ns driver.Namespace, kvs map[driver.PKey]driver.VersionedMetadataValue) map[driver.PKey]error { +func (i *Inspector) SetStateMetadatas(ns driver.Namespace, kvs map[driver.PKey]driver.VaultMetadataValue) map[driver.PKey]error { panic("programming error: the rwset inspector is read-only") } diff --git a/platform/common/core/generic/vault/interceptor.go b/platform/common/core/generic/vault/interceptor.go index b9838d4d4..2321440c9 100644 --- a/platform/common/core/generic/vault/interceptor.go +++ b/platform/common/core/generic/vault/interceptor.go @@ -17,7 +17,7 @@ import ( type VersionedQueryExecutor interface { GetStateMetadata(ctx context.Context, namespace, key string) (driver.Metadata, driver.RawVersion, error) - GetState(ctx context.Context, namespace, key string) (*VersionedRead, error) + GetState(ctx context.Context, namespace, key string) (*driver.VaultRead, error) Done() } diff --git a/platform/common/core/generic/vault/mapper.go b/platform/common/core/generic/vault/mapper.go index ed34a3a88..6821386f6 100644 --- a/platform/common/core/generic/vault/mapper.go +++ b/platform/common/core/generic/vault/mapper.go @@ -13,8 +13,8 @@ import ( ) type VersionBuilder interface { - VersionedValues(rws *ReadWriteSet, ns driver.Namespace, writes NamespaceWrites, block driver.BlockNum, indexInBloc driver.TxNum) (map[driver.PKey]VersionedValue, error) - VersionedMetaValues(rws *ReadWriteSet, ns driver.Namespace, writes KeyedMetaWrites, block driver.BlockNum, indexInBloc driver.TxNum) (map[driver.PKey]driver.VersionedMetadataValue, error) + VersionedValues(rws *ReadWriteSet, ns driver.Namespace, writes NamespaceWrites, block driver.BlockNum, indexInBloc driver.TxNum) (map[driver.PKey]driver.VaultValue, error) + VersionedMetaValues(rws *ReadWriteSet, ns driver.Namespace, writes KeyedMetaWrites, block driver.BlockNum, indexInBloc driver.TxNum) (map[driver.PKey]driver.VaultMetadataValue, error) } type rwSetMapper struct { @@ -31,7 +31,7 @@ func (m *rwSetMapper) mapTxIDs(inputs []commitInput) []driver.TxID { } func (m *rwSetMapper) mapWrites(inputs []commitInput) (driver.Writes, error) { - writes := make(map[driver.Namespace]map[driver.PKey]VersionedValue) + writes := make(map[driver.Namespace]map[driver.PKey]driver.VaultValue) for i, input := range inputs { m.logger.Debugf("input [%d] has [%d] writes", i, len(input.rws.Writes)) for ns, ws := range input.rws.Writes { @@ -50,7 +50,7 @@ func (m *rwSetMapper) mapWrites(inputs []commitInput) (driver.Writes, error) { } func (m *rwSetMapper) mapMetaWrites(inputs []commitInput) (driver.MetaWrites, error) { - metaWrites := make(map[driver.Namespace]map[driver.PKey]driver.VersionedMetadataValue) + metaWrites := make(map[driver.Namespace]map[driver.PKey]driver.VaultMetadataValue) for _, input := range inputs { for ns, ws := range input.rws.MetaWrites { vals, err := m.vb.VersionedMetaValues(input.rws, ns, ws, input.block, input.indexInBloc) diff --git a/platform/common/core/generic/vault/mocks/mocks.go b/platform/common/core/generic/vault/mocks/mocks.go index 0b46b1c29..6a05d3276 100644 --- a/platform/common/core/generic/vault/mocks/mocks.go +++ b/platform/common/core/generic/vault/mocks/mocks.go @@ -14,13 +14,13 @@ import ( ) type MockQE struct { - State driver.VersionedValue + State driver.VaultValue Metadata map[string][]byte } func NewMockQE() MockQE { return MockQE{ - State: driver.VersionedValue{ + State: driver.VaultValue{ Raw: []byte("raw"), Version: blockTxIndexToBytes(1, 1), }, @@ -34,8 +34,8 @@ func (qe MockQE) GetStateMetadata(context.Context, driver.Namespace, driver.PKey return qe.Metadata, blockTxIndexToBytes(1, 1), nil } -func (qe MockQE) GetState(_ context.Context, _ driver.Namespace, pkey driver.PKey) (*driver.VersionedRead, error) { - return &driver.VersionedRead{ +func (qe MockQE) GetState(_ context.Context, _ driver.Namespace, pkey driver.PKey) (*driver.VaultRead, error) { + return &driver.VaultRead{ Key: pkey, Raw: qe.State.Raw, Version: qe.State.Version, diff --git a/platform/common/core/generic/vault/queryexec.go b/platform/common/core/generic/vault/queryexec.go index 07c143520..6c1629dff 100644 --- a/platform/common/core/generic/vault/queryexec.go +++ b/platform/common/core/generic/vault/queryexec.go @@ -10,6 +10,7 @@ import ( "context" "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" "github.com/pkg/errors" ) @@ -52,10 +53,10 @@ func (i *queryExecutor) GetStateMetadata(ctx context.Context, namespace driver.N return i.vaultStore.GetStateMetadata(ctx, namespace, key) } -func (i *queryExecutor) GetState(ctx context.Context, namespace driver.Namespace, key driver.PKey) (*VersionedRead, error) { +func (i *queryExecutor) GetState(ctx context.Context, namespace driver.Namespace, key driver.PKey) (*driver.VaultRead, error) { return i.vaultStore.GetState(ctx, namespace, key) } -func (i *queryExecutor) GetStateRangeScanIterator(ctx context.Context, namespace driver.Namespace, startKey, endKey driver.PKey) (VersionedResultsIterator, error) { +func (i *queryExecutor) GetStateRangeScanIterator(ctx context.Context, namespace driver.Namespace, startKey, endKey driver.PKey) (collections.Iterator[*driver.VaultRead], error) { return i.vaultStore.GetStateRange(ctx, namespace, startKey, endKey) } diff --git a/platform/common/core/generic/vault/vault.go b/platform/common/core/generic/vault/vault.go index d1cbf2138..dc72d82e2 100644 --- a/platform/common/core/generic/vault/vault.go +++ b/platform/common/core/generic/vault/vault.go @@ -48,15 +48,6 @@ type TxStatusStore interface { type NewInterceptorFunc[V driver.ValidationCode] func(logger Logger, ctx context.Context, rwSet ReadWriteSet, qe VersionedQueryExecutor, vaultStore TxStatusStore, txid driver.TxID) TxInterceptor -type ( - VersionedPersistence = dbdriver.VersionedPersistence - VersionedValue = dbdriver.VersionedValue - VersionedMetadataValue = dbdriver.VersionedMetadataValue - VersionedRead = dbdriver.VersionedRead - VersionedResultsIterator = dbdriver.VersionedResultsIterator - QueryExecutor = dbdriver.QueryExecutor -) - type txCommitIndex struct { ctx context.Context txID driver.TxID @@ -118,7 +109,7 @@ func New[V driver.ValidationCode]( return v } -func (db *Vault[V]) NewQueryExecutor(ctx context.Context) (QueryExecutor, error) { +func (db *Vault[V]) NewQueryExecutor(ctx context.Context) (dbdriver.QueryExecutor, error) { return newGlobalLockQueryExecutor(ctx, db.vaultStore) } diff --git a/platform/common/core/generic/vault/vault_test.go b/platform/common/core/generic/vault/vault_test.go index 35fc32cdc..ed02622df 100644 --- a/platform/common/core/generic/vault/vault_test.go +++ b/platform/common/core/generic/vault/vault_test.go @@ -156,7 +156,7 @@ func (m *marshaller) Append(destination *ReadWriteSet, raw []byte, nss ...string } func TestMemory(t *testing.T) { - RemoveNils = func(items []VersionedRead) []VersionedRead { return items } + RemoveNils = func(items []driver2.VaultRead) []driver2.VaultRead { return items } artifactProvider := &testArtifactProvider{} for _, c := range SingleDBCases { ddb, err := vault.OpenMemoryVault() @@ -182,8 +182,8 @@ func TestMemory(t *testing.T) { } func TestSqlite(t *testing.T) { - RemoveNils = func(items []VersionedRead) []VersionedRead { - return slices.DeleteFunc(items, func(e VersionedRead) bool { return e.Raw == nil }) + RemoveNils = func(items []driver2.VaultRead) []driver2.VaultRead { + return slices.DeleteFunc(items, func(e driver2.VaultRead) bool { return e.Raw == nil }) } artifactProvider := &testArtifactProvider{} @@ -210,8 +210,8 @@ func TestSqlite(t *testing.T) { } func TestPostgres(t *testing.T) { - RemoveNils = func(items []VersionedRead) []VersionedRead { - return slices.DeleteFunc(items, func(e VersionedRead) bool { return e.Raw == nil }) + RemoveNils = func(items []driver2.VaultRead) []driver2.VaultRead { + return slices.DeleteFunc(items, func(e driver2.VaultRead) bool { return e.Raw == nil }) } artifactProvider := &testArtifactProvider{} diff --git a/platform/common/core/generic/vault/version.go b/platform/common/core/generic/vault/version.go index 7e129b4e7..eb9bd2f3b 100644 --- a/platform/common/core/generic/vault/version.go +++ b/platform/common/core/generic/vault/version.go @@ -11,7 +11,6 @@ import ( "encoding/binary" driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/pkg/errors" ) @@ -25,18 +24,18 @@ func (b *BlockTxIndexVersionComparator) Equal(a, c driver2.RawVersion) bool { type BlockTxIndexVersionBuilder struct{} -func (b *BlockTxIndexVersionBuilder) VersionedValues(rws *ReadWriteSet, ns driver2.Namespace, writes NamespaceWrites, block driver2.BlockNum, indexInBloc driver2.TxNum) (map[driver2.PKey]VersionedValue, error) { - vals := make(map[driver2.PKey]driver.VersionedValue, len(writes)) +func (b *BlockTxIndexVersionBuilder) VersionedValues(_ *ReadWriteSet, _ driver2.Namespace, writes NamespaceWrites, block driver2.BlockNum, indexInBloc driver2.TxNum) (map[driver2.PKey]driver2.VaultValue, error) { + vals := make(map[driver2.PKey]driver2.VaultValue, len(writes)) for pkey, val := range writes { - vals[pkey] = driver.VersionedValue{Raw: val, Version: BlockTxIndexToBytes(block, indexInBloc)} + vals[pkey] = driver2.VaultValue{Raw: val, Version: BlockTxIndexToBytes(block, indexInBloc)} } return vals, nil } -func (b *BlockTxIndexVersionBuilder) VersionedMetaValues(rws *ReadWriteSet, ns driver2.Namespace, writes KeyedMetaWrites, block driver2.BlockNum, indexInBloc driver2.TxNum) (map[driver2.PKey]driver2.VersionedMetadataValue, error) { - vals := make(map[driver2.PKey]driver2.VersionedMetadataValue, len(writes)) +func (b *BlockTxIndexVersionBuilder) VersionedMetaValues(rws *ReadWriteSet, ns driver2.Namespace, writes KeyedMetaWrites, block driver2.BlockNum, indexInBloc driver2.TxNum) (map[driver2.PKey]driver2.VaultMetadataValue, error) { + vals := make(map[driver2.PKey]driver2.VaultMetadataValue, len(writes)) for pkey, val := range writes { - vals[pkey] = driver2.VersionedMetadataValue{Metadata: val, Version: BlockTxIndexToBytes(block, indexInBloc)} + vals[pkey] = driver2.VaultMetadataValue{Metadata: val, Version: BlockTxIndexToBytes(block, indexInBloc)} } return vals, nil } diff --git a/platform/common/driver/vault.go b/platform/common/driver/vault.go index 184d20650..19587c3b8 100644 --- a/platform/common/driver/vault.go +++ b/platform/common/driver/vault.go @@ -20,18 +20,24 @@ type ( RawVersion = []byte ) -type VersionedRead struct { +type VaultRead struct { Key PKey Raw RawValue Version RawVersion } -type VersionedValue struct { +type UnversionedRead struct { + Key PKey + Raw RawValue +} +type UnversionedValue = RawValue + +type VaultValue struct { Raw RawValue Version RawVersion } -type VersionedMetadataValue struct { +type VaultMetadataValue struct { Version RawVersion Metadata Metadata } @@ -52,12 +58,12 @@ type TxStatus struct { } type TxStatusIterator = collections.Iterator[*TxStatus] -type TxStateIterator = collections.Iterator[*VersionedRead] +type TxStateIterator = collections.Iterator[*VaultRead] -type VersionedResultsIterator = collections.Iterator[*VersionedRead] +type VersionedResultsIterator = collections.Iterator[*VaultRead] type QueryExecutor interface { - GetState(ctx context.Context, namespace Namespace, key PKey) (*VersionedRead, error) + GetState(ctx context.Context, namespace Namespace, key PKey) (*VaultRead, error) GetStateMetadata(ctx context.Context, namespace Namespace, key PKey) (Metadata, RawVersion, error) GetStateRangeScanIterator(ctx context.Context, namespace Namespace, startKey PKey, endKey PKey) (VersionedResultsIterator, error) Done() @@ -100,9 +106,9 @@ type Vault[V comparable] interface { CommitTX(ctx context.Context, txID TxID, block BlockNum, index TxNum) error } -type MetaWrites map[Namespace]map[PKey]VersionedMetadataValue +type MetaWrites map[Namespace]map[PKey]VaultMetadataValue -type Writes map[Namespace]map[PKey]VersionedValue +type Writes map[Namespace]map[PKey]VaultValue // VaultLock represents a lock over a transaction or the whole vault type VaultLock interface { @@ -128,7 +134,7 @@ type VaultStore interface { GetStateMetadata(ctx context.Context, namespace Namespace, key PKey) (Metadata, RawVersion, error) // GetState returns the state for the given specific namespace - key pair - GetState(ctx context.Context, namespace Namespace, key PKey) (*VersionedRead, error) + GetState(ctx context.Context, namespace Namespace, key PKey) (*VaultRead, error) // GetStates returns the states for the given specific namespace - key pairs GetStates(ctx context.Context, namespace Namespace, keys ...PKey) (TxStateIterator, error) diff --git a/platform/fabric/committer.go b/platform/fabric/committer.go index 38772a89d..6b15354e9 100644 --- a/platform/fabric/committer.go +++ b/platform/fabric/committer.go @@ -35,7 +35,7 @@ func (c *Committer) ProcessNamespace(nss ...driver2.Namespace) error { // Status returns a validation code this committer bind to the passed transaction id, plus // a list of dependant transaction ids if they exist. -func (c *Committer) Status(ctx context.Context, txID driver2.TxID) (ValidationCode, string, error) { +func (c *Committer) Status(ctx context.Context, txID driver2.TxID) (driver.ValidationCode, string, error) { return c.committer.Status(ctx, txID) } diff --git a/platform/fabric/core/generic/finality/deliveryflm.go b/platform/fabric/core/generic/finality/deliveryflm.go index d519d7cc4..107fe426d 100644 --- a/platform/fabric/core/generic/finality/deliveryflm.go +++ b/platform/fabric/core/generic/finality/deliveryflm.go @@ -14,6 +14,7 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core/generic/committer" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core/generic/fabricutils" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/core/generic/rwset" + fdriver "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver" "github.com/hyperledger/fabric-protos-go/common" "github.com/pkg/errors" "go.opentelemetry.io/otel/trace/noop" @@ -21,7 +22,7 @@ import ( type txInfo struct { txID driver2.TxID - status fabric.ValidationCode + status fdriver.ValidationCode message string } diff --git a/platform/fabric/core/generic/vault/vault_test.go b/platform/fabric/core/generic/vault/vault_test.go index f8895db73..bfa0ed0c4 100644 --- a/platform/fabric/core/generic/vault/vault_test.go +++ b/platform/fabric/core/generic/vault/vault_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/hyperledger-labs/fabric-smart-client/platform/common/core/generic/vault" + driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" fdriver "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver" dbdriver "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/metrics/disabled" @@ -36,7 +37,7 @@ func (p *artifactsProvider) NewMarshaller() vault.Marshaller { } func TestMemory(t *testing.T) { - vault.RemoveNils = func(items []vault.VersionedRead) []vault.VersionedRead { return items } + vault.RemoveNils = func(items []driver2.VaultRead) []driver2.VaultRead { return items } ap := &artifactsProvider{} for _, c := range vault.SingleDBCases { ddb, err := dbhelper.OpenMemoryVault() @@ -61,8 +62,8 @@ func TestMemory(t *testing.T) { } func TestSqlite(t *testing.T) { - vault.RemoveNils = func(items []vault.VersionedRead) []vault.VersionedRead { - return slices.DeleteFunc(items, func(e vault.VersionedRead) bool { return e.Raw == nil }) + vault.RemoveNils = func(items []driver2.VaultRead) []driver2.VaultRead { + return slices.DeleteFunc(items, func(e driver2.VaultRead) bool { return e.Raw == nil }) } ap := &artifactsProvider{} for _, c := range vault.SingleDBCases { @@ -88,8 +89,8 @@ func TestSqlite(t *testing.T) { } func TestPostgres(t *testing.T) { - vault.RemoveNils = func(items []vault.VersionedRead) []vault.VersionedRead { - return slices.DeleteFunc(items, func(e vault.VersionedRead) bool { return e.Raw == nil }) + vault.RemoveNils = func(items []driver2.VaultRead) []driver2.VaultRead { + return slices.DeleteFunc(items, func(e driver2.VaultRead) bool { return e.Raw == nil }) } ap := &artifactsProvider{} for _, c := range vault.SingleDBCases { diff --git a/platform/fabric/driver/vault.go b/platform/fabric/driver/vault.go index 1ffa52dca..91ad4905d 100644 --- a/platform/fabric/driver/vault.go +++ b/platform/fabric/driver/vault.go @@ -32,7 +32,7 @@ type Vault interface { } type VaultStore interface { - GetState(ctx context.Context, namespace driver.Namespace, key driver.PKey) (*driver.VersionedRead, error) + GetState(ctx context.Context, namespace driver.Namespace, key driver.PKey) (*driver.VaultRead, error) GetStateRange(ctx context.Context, namespace driver.Namespace, startKey, endKey driver.PKey) (driver.TxStateIterator, error) GetLast(ctx context.Context) (*driver.TxStatus, error) } diff --git a/platform/fabric/services/state/vault.go b/platform/fabric/services/state/vault.go index 3c1bffba0..ac6093989 100644 --- a/platform/fabric/services/state/vault.go +++ b/platform/fabric/services/state/vault.go @@ -35,8 +35,6 @@ type Vault interface { GetState(ctx context.Context, namespace driver.Namespace, id driver.PKey, state interface{}) error GetStateCertification(ctx context.Context, namespace driver.Namespace, key driver.PKey) ([]byte, error) - - GetStateByPartialCompositeID(ctx context.Context, ns driver.Namespace, prefix string, attrs []string) (QueryIteratorInterface, error) } // VaultService models a vault instance provider diff --git a/platform/fabric/services/state/vault/vault.go b/platform/fabric/services/state/vault/vault.go index c27b2bb1c..f46141abc 100644 --- a/platform/fabric/services/state/vault/vault.go +++ b/platform/fabric/services/state/vault/vault.go @@ -11,7 +11,6 @@ import ( "encoding/json" "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/fabric" driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/endorser" "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/services/state" @@ -20,32 +19,8 @@ import ( "github.com/pkg/errors" ) -type ListStateQueryIteratorInterface struct { - it fabric.ResultsIterator - next *fabric.Read -} - -func (l *ListStateQueryIteratorInterface) HasNext() bool { - var err error - l.next, err = l.it.Next() - if err != nil || l.next == nil { - return false - } - return true -} - -func (l *ListStateQueryIteratorInterface) Close() error { - l.it.Close() - return nil -} - -func (l *ListStateQueryIteratorInterface) Next(state interface{}) (string, error) { - //log.Printf("It at %s\n", string(l.List[l.Index].Raw)) - return "", json.Unmarshal(l.next.Raw, state) -} - type vaultStore interface { - GetState(ctx context.Context, namespace driver.Namespace, key driver.PKey) (*driver.VersionedRead, error) + GetState(ctx context.Context, namespace driver.Namespace, key driver.PKey) (*driver.VaultRead, error) GetStateRange(ctx context.Context, namespace driver.Namespace, startKey, endKey driver.PKey) (driver.TxStateIterator, error) } type localMembership interface { @@ -75,18 +50,14 @@ func (f *vault) GetState(ctx context.Context, namespace driver.Namespace, id dri return nil } -func (f *vault) GetStateByPartialCompositeID(ctx context.Context, ns driver.Namespace, prefix string, attrs []string) (state.QueryIteratorInterface, error) { +func (f *vault) GetStateByPartialCompositeID(ctx context.Context, ns driver.Namespace, prefix string, attrs []string) (driver.TxStateIterator, error) { startKey, err := state.CreateCompositeKey(prefix, attrs) if err != nil { return nil, err } endKey := startKey + string(state.MaxUnicodeRuneValue) - it, err := f.vaultStore.GetStateRange(ctx, ns, startKey, endKey) - if err != nil { - return nil, errors.Wrap(err, "failed getting state iterator") - } - return &ListStateQueryIteratorInterface{it: it}, nil + return f.vaultStore.GetStateRange(ctx, ns, startKey, endKey) } func (f *vault) GetStateCertification(ctx context.Context, namespace driver.Namespace, key driver.PKey) ([]byte, error) { diff --git a/platform/fabric/vault.go b/platform/fabric/vault.go index 0f58b3b43..cad8a550a 100644 --- a/platform/fabric/vault.go +++ b/platform/fabric/vault.go @@ -11,7 +11,6 @@ import ( "encoding/json" "strings" - "github.com/hyperledger-labs/fabric-smart-client/platform/common/core/generic/vault" "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" fdriver "github.com/hyperledger-labs/fabric-smart-client/platform/fabric/driver" "github.com/pkg/errors" @@ -90,12 +89,6 @@ func (r *RWSet) Equals(rws interface{}, nss ...string) error { } } -type ( - Read = vault.VersionedRead - ResultsIterator = vault.VersionedResultsIterator - ValidationCode = fdriver.ValidationCode -) - type lastTxGetter interface { GetLast(ctx context.Context) (*driver.TxStatus, error) } @@ -125,7 +118,7 @@ func (c *Vault) NewQueryExecutor(ctx context.Context) (driver.QueryExecutor, err return c.vault.NewQueryExecutor(ctx) } -func (c *Vault) Status(ctx context.Context, id driver.TxID) (ValidationCode, string, error) { +func (c *Vault) Status(ctx context.Context, id driver.TxID) (fdriver.ValidationCode, string, error) { return c.vault.Status(ctx, id) } diff --git a/platform/orion/driver/qe.go b/platform/orion/driver/qe.go deleted file mode 100644 index cce70fcb1..000000000 --- a/platform/orion/driver/qe.go +++ /dev/null @@ -1,13 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package driver - -import ( - "github.com/hyperledger-labs/fabric-smart-client/platform/common/core/generic/vault" -) - -type QueryExecutor = vault.QueryExecutor diff --git a/platform/view/core/endpoint/endpoint.go b/platform/view/core/endpoint/endpoint.go index b0c01504a..fa04ecf36 100644 --- a/platform/view/core/endpoint/endpoint.go +++ b/platform/view/core/endpoint/endpoint.go @@ -165,9 +165,7 @@ func (r *Service) matchesResolver(endpoint string, pkID []byte, resolver *Resolv } func (r *Service) AddResolver(name string, domain string, addresses map[string]string, aliases []string, id []byte) (view.Identity, error) { - if logger.IsEnabledFor(zapcore.DebugLevel) { - logger.Debugf("adding resolver [%s,%s,%v,%v,%s]", name, domain, addresses, aliases, view.Identity(id).String()) - } + logger.Infof("adding resolver [%s,%s,%v,%v,%s]", name, domain, addresses, aliases, view.Identity(id)) // is there a resolver with the same name or clashing aliases? r.resolversMutex.RLock() @@ -260,6 +258,7 @@ func (r *Service) rootEndpoint(party view.Identity) (*Resolver, error) { defer r.resolversMutex.RUnlock() for _, resolver := range r.resolvers { + logger.Infof("Compare [%s] [%s]", party.UniqueID(), view.Identity(resolver.Id).UniqueID()) if bytes.Equal(resolver.Id, party) { return resolver, nil } diff --git a/platform/view/services/db/dbtest/bench.go b/platform/view/services/db/dbtest/bench.go index ab7c06dd2..fdda6e256 100644 --- a/platform/view/services/db/dbtest/bench.go +++ b/platform/view/services/db/dbtest/bench.go @@ -21,16 +21,16 @@ var ( payload = []byte("hallo") ) -func ReadExisting(b *testing.B, db driver.TransactionalVersionedPersistence) { +func ReadExisting(b *testing.B, db driver.UnversionedPersistence) { assert.NoError(b, db.BeginUpdate()) - assert.NoError(b, db.SetState(namespace, key, driver.VersionedValue{Raw: payload})) + assert.NoError(b, db.SetState(namespace, key, payload)) assert.NoError(b, db.Commit()) var v []byte b.ResetTimer() for i := 0; i < b.N; i++ { vv, _ := db.GetState(namespace, key) - v = vv.Raw + v = vv } b.StopTimer() returnValue = v @@ -38,12 +38,12 @@ func ReadExisting(b *testing.B, db driver.TransactionalVersionedPersistence) { b.Logf("%.0f reads per second from same key", float64(b.N)/b.Elapsed().Seconds()) } -func ReadNonExisting(b *testing.B, db driver.TransactionalVersionedPersistence) { +func ReadNonExisting(b *testing.B, db driver.UnversionedPersistence) { var v []byte b.ResetTimer() for i := 0; i < b.N; i++ { vv, _ := db.GetState(namespace, key) - v = vv.Raw + v = vv } b.StopTimer() returnValue = v @@ -51,13 +51,13 @@ func ReadNonExisting(b *testing.B, db driver.TransactionalVersionedPersistence) b.Logf("%.0f reads per second to nonexistent keys", float64(b.N)/b.Elapsed().Seconds()) } -func WriteOne(b *testing.B, db driver.TransactionalVersionedPersistence) { +func WriteOne(b *testing.B, db driver.UnversionedPersistence) { var err error b.ResetTimer() for i := 0; i < b.N; i++ { err = db.BeginUpdate() _ = err - err = db.SetState(namespace, key, driver.VersionedValue{Raw: payload}) + err = db.SetState(namespace, key, payload) _ = err err = db.Commit() } @@ -67,7 +67,7 @@ func WriteOne(b *testing.B, db driver.TransactionalVersionedPersistence) { b.Logf("%.0f writes per second to same key", float64(b.N)/b.Elapsed().Seconds()) } -func WriteMany(b *testing.B, db driver.TransactionalVersionedPersistence) { +func WriteMany(b *testing.B, db driver.UnversionedPersistence) { var err error var k string b.Logf("before: %+v", db.Stats()) @@ -78,7 +78,7 @@ func WriteMany(b *testing.B, db driver.TransactionalVersionedPersistence) { err = db.BeginUpdate() _ = err - err = db.SetState(namespace, k, driver.VersionedValue{Raw: payload}) + err = db.SetState(namespace, k, payload) _ = err err = db.Commit() @@ -93,7 +93,7 @@ func WriteMany(b *testing.B, db driver.TransactionalVersionedPersistence) { b.Logf("after: %+v", db.Stats()) } -func WriteParallel(b *testing.B, db driver.TransactionalUnversionedPersistence) { +func WriteParallel(b *testing.B, db driver.UnversionedPersistence) { var err error var k string var i int diff --git a/platform/view/services/db/dbtest/helpers.go b/platform/view/services/db/dbtest/helpers.go index d91df630d..f36e38ab2 100644 --- a/platform/view/services/db/dbtest/helpers.go +++ b/platform/view/services/db/dbtest/helpers.go @@ -28,13 +28,11 @@ import ( // This file exposes functions that db drivers can use for integration tests var Cases = []struct { Name string - Fn func(*testing.T, driver.TransactionalVersionedPersistence) + Fn func(*testing.T, driver.UnversionedPersistence) }{ {"RangeQueries", TTestRangeQueries}, - {"Meta", TTestMeta}, {"SimpleReadWrite", TTestSimpleReadWrite}, {"GetNonExistent", TTestGetNonExistent}, - {"Metadata", TTestMetadata}, {"DB1", TTestDB1}, {"DB2", TTestDB2}, {"RangeQueries1", TTestRangeQueries1}, @@ -59,13 +57,6 @@ var UnversionedNotifierCases = []struct { {"UnversionedNotifierSimple", TTestUnversionedNotifierSimple}, } -var VersionedNotifierCases = []struct { - Name string - Fn func(*testing.T, driver.VersionedNotifier) -}{ - {"VersionedNotifierSimple", TTestVersionedNotifierSimple}, -} - var ErrorCases = []struct { Name string Fn func(t *testing.T, readDB *sql.DB, writeDB *sql.DB, errorWrapper driver.SQLErrorWrapper, table string) @@ -92,7 +83,7 @@ func TTestDuplicate(t *testing.T, _ *sql.DB, writeDB *sql.DB, errorWrapper drive assert.NoError(t, err, "should rollback") } -func TTestRangeQueries(t *testing.T, db driver.TransactionalVersionedPersistence) { +func TTestRangeQueries(t *testing.T, db driver.UnversionedPersistence) { ns := "namespace" populateForRangeQueries(t, db, ns) @@ -101,21 +92,21 @@ func TTestRangeQueries(t *testing.T, db driver.TransactionalVersionedPersistence res, err := collections.ReadAll(itr) assert.NoError(t, err) assert.Len(t, res, 4) - assert.Equal(t, []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k111", Raw: []byte("k111_value"), Version: ToBytes(35, 4)}, - {Key: "k2", Raw: []byte("k2_value"), Version: ToBytes(35, 1)}, - {Key: "k3", Raw: []byte("k3_value"), Version: ToBytes(35, 2)}, + assert.Equal(t, []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k111", Raw: []byte("k111_value")}, + {Key: "k2", Raw: []byte("k2_value")}, + {Key: "k3", Raw: []byte("k3_value")}, }, res) itr, err = db.GetStateRangeScanIterator(ns, "k1", "k3") assert.NoError(t, err) res, err = collections.ReadAll(itr) assert.NoError(t, err) - expected := []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k111", Raw: []byte("k111_value"), Version: ToBytes(35, 4)}, - {Key: "k2", Raw: []byte("k2_value"), Version: ToBytes(35, 1)}, + expected := []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k111", Raw: []byte("k111_value")}, + {Key: "k2", Raw: []byte("k2_value")}, } assert.Len(t, res, 3) assert.Equal(t, expected, res) @@ -124,17 +115,17 @@ func TTestRangeQueries(t *testing.T, db driver.TransactionalVersionedPersistence assert.NoError(t, err) res, err = collections.ReadFirst(itr, 2) assert.NoError(t, err) - expected = []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k111", Raw: []byte("k111_value"), Version: ToBytes(35, 4)}, + expected = []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k111", Raw: []byte("k111_value")}, } assert.Len(t, res, 2) assert.Equal(t, expected, res) - expected = []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k111", Raw: []byte("k111_value"), Version: ToBytes(35, 4)}, - {Key: "k2", Raw: []byte("k2_value"), Version: ToBytes(35, 1)}, + expected = []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k111", Raw: []byte("k111_value")}, + {Key: "k2", Raw: []byte("k2_value")}, } itr, err = db.GetStateRangeScanIterator(ns, "k1", "k3") assert.NoError(t, err) @@ -143,9 +134,9 @@ func TTestRangeQueries(t *testing.T, db driver.TransactionalVersionedPersistence assert.Len(t, res, 3) assert.Equal(t, expected, res) - expected = []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k3", Raw: []byte("k3_value"), Version: ToBytes(35, 2)}, + expected = []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k3", Raw: []byte("k3_value")}, } itr, err = db.GetStateSetIterator(ns, "k1", "k3") assert.NoError(t, err) @@ -157,75 +148,19 @@ func TTestRangeQueries(t *testing.T, db driver.TransactionalVersionedPersistence } } -func TTestMeta(t *testing.T, db driver.TransactionalVersionedPersistence) { - ns := "ns" - key := "key" - - err := db.BeginUpdate() - assert.NoError(t, err) - - err = db.SetState(ns, key, driver.VersionedValue{Raw: []byte("val"), Version: ToBytes(35, 1)}) - assert.NoError(t, err) - - err = db.Commit() - assert.NoError(t, err) - - vv, err := db.GetState(ns, key) - assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{Raw: []byte("val"), Version: ToBytes(35, 1)}, vv) - - m, ver, err := db.GetStateMetadata(ns, key) - assert.NoError(t, err) - assert.Len(t, m, 0) - bn, tn, err := FromBytes(ver) - assert.NoError(t, err) - assert.Equal(t, uint64(35), bn) - assert.Equal(t, uint64(1), tn) - - err = db.BeginUpdate() - assert.NoError(t, err) - - err = db.SetStateMetadata(ns, key, map[string][]byte{"foo": []byte("bar")}, ToBytes(36, 2)) - assert.NoError(t, err) - - err = db.Commit() - assert.NoError(t, err) - - vv, err = db.GetState(ns, key) - assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{Raw: []byte("val"), Version: ToBytes(36, 2)}, vv) - - m, ver, err = db.GetStateMetadata(ns, key) - assert.NoError(t, err) - bn, tn, err = FromBytes(ver) - assert.NoError(t, err) - assert.Equal(t, map[string][]byte{"foo": []byte("bar")}, m) - assert.Equal(t, uint64(36), bn) - assert.Equal(t, uint64(2), tn) -} - -func TTestSimpleReadWrite(t *testing.T, db driver.TransactionalVersionedPersistence) { +func TTestSimpleReadWrite(t *testing.T, db driver.UnversionedPersistence) { ns := "ns" key := "key" // empty state vv, err := db.GetState(ns, key) assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{}, vv) - - // empty metadata - m, ver, err := db.GetStateMetadata(ns, key) - assert.NoError(t, err) - bn, tn, err := FromBytes(ver) - assert.NoError(t, err) - assert.Len(t, m, 0) - assert.Equal(t, uint64(0), bn) - assert.Equal(t, uint64(0), tn) + assert.Equal(t, driver.UnversionedValue{}, vv) // add data err = db.BeginUpdate() assert.NoError(t, err) - err = db.SetState(ns, key, driver.VersionedValue{Raw: []byte("val"), Version: ToBytes(35, 1)}) + err = db.SetState(ns, key, driver.UnversionedValue("val")) assert.NoError(t, err) err = db.Commit() assert.NoError(t, err) @@ -233,30 +168,30 @@ func TTestSimpleReadWrite(t *testing.T, db driver.TransactionalVersionedPersiste // get data vv, err = db.GetState(ns, key) assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{Raw: []byte("val"), Version: ToBytes(35, 1)}, vv) + assert.Equal(t, driver.UnversionedValue("val"), vv) // logging because this can cause a deadlock if maxOpenConnections is only 1 t.Logf("get state [%s] during set state tx", key) err = db.BeginUpdate() assert.NoError(t, err) - err = db.SetState(ns, key, driver.VersionedValue{Raw: []byte("val1"), Version: ToBytes(36, 2)}) + err = db.SetState(ns, key, driver.UnversionedValue("val1")) assert.NoError(t, err) vv, err = db.GetState(ns, key) assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{Raw: []byte("val"), Version: ToBytes(35, 1)}, vv) + assert.Equal(t, driver.UnversionedValue("val"), vv) err = db.Commit() assert.NoError(t, err) t.Logf("get state after tx [%s]", key) vv, err = db.GetState(ns, key) assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{Raw: []byte("val1"), Version: ToBytes(36, 2)}, vv) + assert.Equal(t, driver.UnversionedValue("val1"), vv) // Discard an update err = db.BeginUpdate() assert.NoError(t, err) - err = db.SetState(ns, key, driver.VersionedValue{Raw: []byte("val0"), Version: ToBytes(37, 3)}) + err = db.SetState(ns, key, driver.UnversionedValue("val0")) assert.NoError(t, err) err = db.Discard() assert.NoError(t, err) @@ -264,7 +199,7 @@ func TTestSimpleReadWrite(t *testing.T, db driver.TransactionalVersionedPersiste // Expect state to be same as before the rollback vv, err = db.GetState(ns, key) assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{Raw: []byte("val1"), Version: ToBytes(36, 2)}, vv) + assert.Equal(t, driver.UnversionedValue("val1"), vv) // delete state err = db.BeginUpdate() @@ -277,17 +212,17 @@ func TTestSimpleReadWrite(t *testing.T, db driver.TransactionalVersionedPersiste // expect state to be empty vv, err = db.GetState(ns, key) assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{}, vv) + assert.Equal(t, driver.UnversionedValue{}, vv) } -func populateDB(t *testing.T, db driver.TransactionalVersionedPersistence, ns, key, keyWithSuffix string) { +func populateDB(t *testing.T, db driver.UnversionedPersistence, ns, key, keyWithSuffix string) { err := db.BeginUpdate() assert.NoError(t, err) - err = db.SetState(ns, key, driver.VersionedValue{Raw: []byte("bar"), Version: ToBytes(1, 1)}) + err = db.SetState(ns, key, driver.UnversionedValue("bar")) assert.NoError(t, err) - err = db.SetState(ns, keyWithSuffix, driver.VersionedValue{Raw: []byte("bar1"), Version: ToBytes(1, 1)}) + err = db.SetState(ns, keyWithSuffix, driver.UnversionedValue("bar1")) assert.NoError(t, err) err = db.Commit() @@ -295,91 +230,48 @@ func populateDB(t *testing.T, db driver.TransactionalVersionedPersistence, ns, k vv, err := db.GetState(ns, key) assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{Raw: []byte("bar"), Version: ToBytes(1, 1)}, vv) + assert.Equal(t, driver.UnversionedValue("bar"), vv) vv, err = db.GetState(ns, keyWithSuffix) assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{Raw: []byte("bar1"), Version: ToBytes(1, 1)}, vv) + assert.Equal(t, driver.UnversionedValue("bar1"), vv) vv, err = db.GetState(ns, "barf") assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{}, vv) + assert.Equal(t, driver.UnversionedValue{}, vv) vv, err = db.GetState("barf", "barf") assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{}, vv) + assert.Equal(t, driver.UnversionedValue{}, vv) } -func populateForRangeQueries(t *testing.T, db driver.TransactionalVersionedPersistence, ns string) { +func populateForRangeQueries(t *testing.T, db driver.UnversionedPersistence, ns string) { err := db.BeginUpdate() assert.NoError(t, err) - err = db.SetState(ns, "k2", driver.VersionedValue{Raw: []byte("k2_value"), Version: ToBytes(35, 1)}) + err = db.SetState(ns, "k2", driver.UnversionedValue("k2_value")) assert.NoError(t, err) - err = db.SetState(ns, "k3", driver.VersionedValue{Raw: []byte("k3_value"), Version: ToBytes(35, 2)}) + err = db.SetState(ns, "k3", driver.UnversionedValue("k3_value")) assert.NoError(t, err) - err = db.SetState(ns, "k1", driver.VersionedValue{Raw: []byte("k1_value"), Version: ToBytes(35, 3)}) + err = db.SetState(ns, "k1", driver.UnversionedValue("k1_value")) assert.NoError(t, err) - err = db.SetState(ns, "k111", driver.VersionedValue{Raw: []byte("k111_value"), Version: ToBytes(35, 4)}) + err = db.SetState(ns, "k111", driver.UnversionedValue("k111_value")) assert.NoError(t, err) err = db.Commit() assert.NoError(t, err) } -func TTestGetNonExistent(t *testing.T, db driver.TransactionalVersionedPersistence) { +func TTestGetNonExistent(t *testing.T, db driver.UnversionedPersistence) { ns := "namespace" key := "foo" vv, err := db.GetState(ns, key) assert.NoError(t, err) - assert.Equal(t, driver.VersionedValue{}, vv) + assert.Equal(t, driver.UnversionedValue{}, vv) } -func TTestMetadata(t *testing.T, db driver.TransactionalVersionedPersistence) { - ns := "namespace" - key := "foo" - - md, ver, err := db.GetStateMetadata(ns, key) - assert.NoError(t, err) - assert.Nil(t, md) - bn, txn, err := FromBytes(ver) - assert.NoError(t, err) - assert.Equal(t, uint64(0x0), bn) - assert.Equal(t, uint64(0x0), txn) - - err = db.BeginUpdate() - assert.NoError(t, err) - err = db.SetStateMetadata(ns, key, map[string][]byte{"foo": []byte("bar")}, ToBytes(35, 1)) - assert.NoError(t, err) - err = db.Commit() - assert.NoError(t, err) - - md, ver, err = db.GetStateMetadata(ns, key) - assert.NoError(t, err) - bn, txn, err = FromBytes(ver) - assert.NoError(t, err) - assert.Equal(t, map[string][]byte{"foo": []byte("bar")}, md) - assert.Equal(t, uint64(35), bn) - assert.Equal(t, uint64(1), txn) - - err = db.BeginUpdate() - assert.NoError(t, err) - err = db.SetStateMetadata(ns, key, map[string][]byte{"foo1": []byte("bar1")}, ToBytes(36, 2)) - assert.NoError(t, err) - err = db.Commit() - assert.NoError(t, err) - - md, ver, err = db.GetStateMetadata(ns, key) - assert.NoError(t, err) - bn, txn, err = FromBytes(ver) - assert.NoError(t, err) - assert.Equal(t, map[string][]byte{"foo1": []byte("bar1")}, md) - assert.Equal(t, uint64(36), bn) - assert.Equal(t, uint64(2), txn) -} - -func TTestDB1(t *testing.T, db driver.TransactionalVersionedPersistence) { +func TTestDB1(t *testing.T, db driver.UnversionedPersistence) { ns := "namespace" key := "foo" keyWithSuffix := key + "/suffix" @@ -399,7 +291,7 @@ func TTestDB1(t *testing.T, db driver.TransactionalVersionedPersistence) { assert.NoError(t, err) } -func TTestDB2(t *testing.T, db driver.TransactionalVersionedPersistence) { +func TTestDB2(t *testing.T, db driver.UnversionedPersistence) { ns := "namespace" key := "foo" keyWithSuffix := key + "/suffix" @@ -419,19 +311,19 @@ func TTestDB2(t *testing.T, db driver.TransactionalVersionedPersistence) { assert.NoError(t, err) } -func TTestRangeQueries1(t *testing.T, db driver.TransactionalVersionedPersistence) { +func TTestRangeQueries1(t *testing.T, db driver.UnversionedPersistence) { ns := "namespace" err := db.BeginUpdate() assert.NoError(t, err) - err = db.SetState(ns, "k2", driver.VersionedValue{Raw: []byte("k2_value"), Version: ToBytes(35, 1)}) + err = db.SetState(ns, "k2", driver.UnversionedValue("k2_value")) assert.NoError(t, err) - err = db.SetState(ns, "k3", driver.VersionedValue{Raw: []byte("k3_value"), Version: ToBytes(35, 2)}) + err = db.SetState(ns, "k3", driver.UnversionedValue("k3_value")) assert.NoError(t, err) - err = db.SetState(ns, "k1", driver.VersionedValue{Raw: []byte("k1_value"), Version: ToBytes(35, 3)}) + err = db.SetState(ns, "k1", driver.UnversionedValue("k1_value")) assert.NoError(t, err) - err = db.SetState(ns, "k111", driver.VersionedValue{Raw: []byte("k111_value"), Version: ToBytes(35, 4)}) + err = db.SetState(ns, "k111", driver.UnversionedValue("k111_value")) assert.NoError(t, err) err = db.Commit() @@ -442,11 +334,11 @@ func TTestRangeQueries1(t *testing.T, db driver.TransactionalVersionedPersistenc res, err := collections.ReadAll(itr) assert.NoError(t, err) assert.Len(t, res, 4) - assert.Equal(t, []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k111", Raw: []byte("k111_value"), Version: ToBytes(35, 4)}, - {Key: "k2", Raw: []byte("k2_value"), Version: ToBytes(35, 1)}, - {Key: "k3", Raw: []byte("k3_value"), Version: ToBytes(35, 2)}, + assert.Equal(t, []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k111", Raw: []byte("k111_value")}, + {Key: "k2", Raw: []byte("k2_value")}, + {Key: "k3", Raw: []byte("k3_value")}, }, res) itr, err = db.GetStateRangeScanIterator(ns, "k1", "k3") @@ -454,40 +346,40 @@ func TTestRangeQueries1(t *testing.T, db driver.TransactionalVersionedPersistenc res, err = collections.ReadAll(itr) assert.NoError(t, err) assert.Len(t, res, 3) - assert.Equal(t, []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k111", Raw: []byte("k111_value"), Version: ToBytes(35, 4)}, - {Key: "k2", Raw: []byte("k2_value"), Version: ToBytes(35, 1)}, + assert.Equal(t, []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k111", Raw: []byte("k111_value")}, + {Key: "k2", Raw: []byte("k2_value")}, }, res) } -func TTestMultiWritesAndRangeQueries(t *testing.T, db driver.TransactionalVersionedPersistence) { +func TTestMultiWritesAndRangeQueries(t *testing.T, db driver.UnversionedPersistence) { ns := "namespace" assert.NoError(t, db.BeginUpdate()) - assert.NoError(t, db.SetState(ns, "k2", driver.VersionedValue{Raw: []byte("k2_value"), Version: ToBytes(35, 1)})) - assert.NoError(t, db.SetState(ns, "k3", driver.VersionedValue{Raw: []byte("k3_value"), Version: ToBytes(35, 2)})) - assert.NoError(t, db.SetState(ns, "k1", driver.VersionedValue{Raw: []byte("k1_value"), Version: ToBytes(35, 3)})) - assert.NoError(t, db.SetState(ns, "k111", driver.VersionedValue{Raw: []byte("k111_value"), Version: ToBytes(35, 4)})) + assert.NoError(t, db.SetState(ns, "k2", driver.UnversionedValue("k2_value"))) + assert.NoError(t, db.SetState(ns, "k3", driver.UnversionedValue("k3_value"))) + assert.NoError(t, db.SetState(ns, "k1", driver.UnversionedValue("k1_value"))) + assert.NoError(t, db.SetState(ns, "k111", driver.UnversionedValue("k111_value"))) assert.NoError(t, db.Commit()) var wg sync.WaitGroup wg.Add(4) go func() { - write(t, db, ns, "k2", []byte("k2_value"), 35, 1) + write(t, db, ns, "k2", []byte("k2_value")) wg.Done() }() go func() { - write(t, db, ns, "k3", []byte("k3_value"), 35, 2) + write(t, db, ns, "k3", []byte("k3_value")) wg.Done() }() go func() { - write(t, db, ns, "k1", []byte("k1_value"), 35, 3) + write(t, db, ns, "k1", []byte("k1_value")) wg.Done() }() go func() { - write(t, db, ns, "k111", []byte("k111_value"), 35, 4) + write(t, db, ns, "k111", []byte("k111_value")) wg.Done() }() wg.Wait() @@ -497,21 +389,21 @@ func TTestMultiWritesAndRangeQueries(t *testing.T, db driver.TransactionalVersio res, err := collections.ReadAll(itr) assert.NoError(t, err) assert.Len(t, res, 4) - assert.Equal(t, []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k111", Raw: []byte("k111_value"), Version: ToBytes(35, 4)}, - {Key: "k2", Raw: []byte("k2_value"), Version: ToBytes(35, 1)}, - {Key: "k3", Raw: []byte("k3_value"), Version: ToBytes(35, 2)}, + assert.Equal(t, []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k111", Raw: []byte("k111_value")}, + {Key: "k2", Raw: []byte("k2_value")}, + {Key: "k3", Raw: []byte("k3_value")}, }, res) itr, err = db.GetStateRangeScanIterator(ns, "k1", "k3") assert.NoError(t, err) res, err = collections.ReadAll(itr) assert.NoError(t, err) - expected := []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k111", Raw: []byte("k111_value"), Version: ToBytes(35, 4)}, - {Key: "k2", Raw: []byte("k2_value"), Version: ToBytes(35, 1)}, + expected := []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k111", Raw: []byte("k111_value")}, + {Key: "k2", Raw: []byte("k2_value")}, } assert.Len(t, res, 3) assert.Equal(t, expected, res) @@ -520,17 +412,17 @@ func TTestMultiWritesAndRangeQueries(t *testing.T, db driver.TransactionalVersio assert.NoError(t, err) res, err = collections.ReadFirst(itr, 2) assert.NoError(t, err) - expected = []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k111", Raw: []byte("k111_value"), Version: ToBytes(35, 4)}, + expected = []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k111", Raw: []byte("k111_value")}, } assert.Len(t, res, 2) assert.Equal(t, expected, res) - expected = []driver.VersionedRead{ - {Key: "k1", Raw: []byte("k1_value"), Version: ToBytes(35, 3)}, - {Key: "k111", Raw: []byte("k111_value"), Version: ToBytes(35, 4)}, - {Key: "k2", Raw: []byte("k2_value"), Version: ToBytes(35, 1)}, + expected = []driver.UnversionedRead{ + {Key: "k1", Raw: []byte("k1_value")}, + {Key: "k111", Raw: []byte("k111_value")}, + {Key: "k2", Raw: []byte("k2_value")}, } itr, err = db.GetStateRangeScanIterator(ns, "k1", "k3") assert.NoError(t, err) @@ -540,32 +432,24 @@ func TTestMultiWritesAndRangeQueries(t *testing.T, db driver.TransactionalVersio assert.Equal(t, expected, res) } -func TTestMultiWrites(t *testing.T, db driver.TransactionalVersionedPersistence) { +func TTestMultiWrites(t *testing.T, db driver.UnversionedPersistence) { ns := "namespace" var wg sync.WaitGroup n := 20 wg.Add(n) for i := 0; i < n; i++ { go func(i int) { - write( - t, - db, - ns, - fmt.Sprintf("TTestMultiWrites_key_%d", i), - []byte(fmt.Sprintf("TTestMultiWrites_value_%d", i)), - 35, - 1, - ) + write(t, db, ns, fmt.Sprintf("TTestMultiWrites_key_%d", i), []byte(fmt.Sprintf("TTestMultiWrites_value_%d", i))) wg.Done() }(i) } wg.Wait() } -func write(t *testing.T, db driver.TransactionalVersionedPersistence, ns, key string, value []byte, block, txnum uint64) { +func write(t *testing.T, db driver.UnversionedPersistence, ns, key string, value []byte) { tx, err := db.NewWriteTransaction() assert.NoError(t, err) - err = tx.SetState(ns, key, driver.VersionedValue{Raw: value, Version: ToBytes(block, txnum)}) + err = tx.SetState(ns, key, value) assert.NoError(t, err) err = tx.Commit() assert.NoError(t, err) @@ -604,7 +488,7 @@ func createCompositeKey(objectType string, attributes []string) (string, error) return ck, nil } -func TTestCompositeKeys(t *testing.T, db driver.TransactionalVersionedPersistence) { +func TTestCompositeKeys(t *testing.T, db driver.UnversionedPersistence) { ns := "namespace" keyPrefix := "prefix" @@ -619,7 +503,7 @@ func TTestCompositeKeys(t *testing.T, db driver.TransactionalVersionedPersistenc } { k, err := createCompositeKey(keyPrefix, comps) assert.NoError(t, err) - err = db.SetState(ns, k, driver.VersionedValue{Raw: []byte(k), Version: ToBytes(35, 1)}) + err = db.SetState(ns, k, driver.UnversionedValue(k)) assert.NoError(t, err) } @@ -635,17 +519,17 @@ func TTestCompositeKeys(t *testing.T, db driver.TransactionalVersionedPersistenc assert.NoError(t, err) defer itr.Close() - res := make([]driver.VersionedRead, 0, 4) + res := make([]driver.UnversionedRead, 0, 4) for n, err := itr.Next(); n != nil; n, err = itr.Next() { assert.NoError(t, err) res = append(res, *n) } assert.Len(t, res, 4) - assert.Equal(t, []driver.VersionedRead{ - {Key: "\x00prefix0a0b0", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30}, Version: ToBytes(0x23, 1)}, - {Key: "\x00prefix0a0b010", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30, 0x31, 0x30}, Version: ToBytes(0x23, 1)}, - {Key: "\x00prefix0a0b030", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30, 0x33, 0x30}, Version: ToBytes(0x23, 1)}, - {Key: "\x00prefix0a0d0", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x64, 0x30}, Version: ToBytes(0x23, 1)}, + assert.Equal(t, []driver.UnversionedRead{ + {Key: "\x00prefix0a0b0", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30}}, + {Key: "\x00prefix0a0b010", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30, 0x31, 0x30}}, + {Key: "\x00prefix0a0b030", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30, 0x33, 0x30}}, + {Key: "\x00prefix0a0d0", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x64, 0x30}}, }, res) partialCompositeKey, err = createCompositeKey(keyPrefix, []string{"a", "b"}) @@ -657,16 +541,16 @@ func TTestCompositeKeys(t *testing.T, db driver.TransactionalVersionedPersistenc assert.NoError(t, err) defer itr.Close() - res = make([]driver.VersionedRead, 0, 2) + res = make([]driver.UnversionedRead, 0, 2) for n, err := itr.Next(); n != nil; n, err = itr.Next() { assert.NoError(t, err) res = append(res, *n) } assert.Len(t, res, 3) - assert.Equal(t, []driver.VersionedRead{ - {Key: "\x00prefix0a0b0", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30}, Version: ToBytes(0x23, 1)}, - {Key: "\x00prefix0a0b010", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30, 0x31, 0x30}, Version: ToBytes(0x23, 1)}, - {Key: "\x00prefix0a0b030", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30, 0x33, 0x30}, Version: ToBytes(0x23, 1)}, + assert.Equal(t, []driver.UnversionedRead{ + {Key: "\x00prefix0a0b0", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30}}, + {Key: "\x00prefix0a0b010", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30, 0x31, 0x30}}, + {Key: "\x00prefix0a0b030", Raw: []uint8{0x0, 0x70, 0x72, 0x65, 0x66, 0x69, 0x78, 0x30, 0x61, 0x30, 0x62, 0x30, 0x33, 0x30}}, }, res) } @@ -976,74 +860,6 @@ func TTestUnversionedNotifierSimple(t *testing.T, db driver.UnversionedNotifier) assert.Equal(t, []notifyEvent{{upsert, "ns", "key"}, {upsert, "ns", "key"}, {delete, "ns", "key"}}, results) } -func TTestVersionedNotifierSimple(t *testing.T, db driver.VersionedNotifier) { - ch, err := subscribe(db) - assert.NoError(t, err) - - ns := "ns" - key := "key" - - vv, err := db.GetState(ns, key) - assert.NoError(t, err) - assert.Equal(t, []byte(nil), vv.Raw) - - err = db.BeginUpdate() - assert.NoError(t, err) - err = db.SetState(ns, key, driver.VersionedValue{Raw: []byte("val")}) - assert.NoError(t, err) - err = db.Commit() - assert.NoError(t, err) - - vv, err = db.GetState(ns, key) - assert.NoError(t, err) - assert.Equal(t, []byte("val"), vv.Raw) - - err = db.BeginUpdate() - assert.NoError(t, err) - - err = db.SetState(ns, key, driver.VersionedValue{Raw: []byte("val1")}) - assert.NoError(t, err) - - vv, err = db.GetState(ns, key) - assert.NoError(t, err) - assert.Equal(t, []byte("val"), vv.Raw) - - err = db.Commit() - assert.NoError(t, err) - - vv, err = db.GetState(ns, key) - assert.NoError(t, err) - assert.Equal(t, []byte("val1"), vv.Raw) - - // Discard an update - err = db.BeginUpdate() - assert.NoError(t, err) - err = db.SetState(ns, key, driver.VersionedValue{Raw: []byte("val0")}) - assert.NoError(t, err) - err = db.Discard() - assert.NoError(t, err) - - // Expect state to be same as before the rollback - vv, err = db.GetState(ns, key) - assert.NoError(t, err) - assert.Equal(t, []byte("val1"), vv.Raw) - - err = db.BeginUpdate() - assert.NoError(t, err) - err = db.DeleteState(ns, key) - assert.NoError(t, err) - err = db.Commit() - assert.NoError(t, err) - - vv, err = db.GetState(ns, key) - assert.NoError(t, err) - assert.Equal(t, []byte(nil), vv.Raw) - - results, err := waitForResults(ch, 3, 1*time.Second) - assert.NoError(t, err) - assert.Equal(t, []notifyEvent{{upsert, "ns", "key"}, {upsert, "ns", "key"}, {delete, "ns", "key"}}, results) -} - type opType int const ( diff --git a/platform/view/services/db/driver/driver.go b/platform/view/services/db/driver/driver.go index 2485eb6a0..23affa4b5 100644 --- a/platform/view/services/db/driver/driver.go +++ b/platform/view/services/db/driver/driver.go @@ -21,22 +21,8 @@ var ( type SQLError = error -type VersionedValue = driver.VersionedValue - -type VersionedMetadataValue = driver.VersionedMetadataValue - -type UnversionedRead struct { - Key driver.PKey - Raw driver.RawValue -} - -type UnversionedResultsIterator = collections.Iterator[*UnversionedRead] - -type UnversionedValue = driver.RawValue - -type VersionedRead = driver.VersionedRead - -type VersionedResultsIterator = collections.Iterator[*VersionedRead] +type UnversionedRead = driver.UnversionedRead +type UnversionedValue = driver.UnversionedValue type QueryExecutor = driver.QueryExecutor @@ -59,13 +45,14 @@ type EnvelopePersistence = driver.EnvelopeStore[string] type VaultPersistence = driver.VaultStore -type BasePersistence[V any, R any] interface { +// UnversionedPersistence models a key-value storage place +type UnversionedPersistence interface { // SetState sets the given value for the given namespace, key, and version - SetState(namespace driver.Namespace, key driver.PKey, value V) error + SetState(namespace driver.Namespace, key driver.PKey, value driver.UnversionedValue) error // SetStates sets the given values for the given namespace, key, and version - SetStates(namespace driver.Namespace, kvs map[driver.PKey]V) map[driver.PKey]error + SetStates(namespace driver.Namespace, kvs map[driver.PKey]driver.UnversionedValue) map[driver.PKey]error // GetState gets the value and version for given namespace and key - GetState(namespace driver.Namespace, key driver.PKey) (V, error) + GetState(namespace driver.Namespace, key driver.PKey) (driver.UnversionedValue, error) // DeleteState deletes the given namespace and key DeleteState(namespace driver.Namespace, key driver.PKey) error // DeleteStates deletes the given namespace and keys @@ -74,11 +61,10 @@ type BasePersistence[V any, R any] interface { // startKey is included in the results and endKey is excluded. An empty startKey refers to the first available key // and an empty endKey refers to the last available key. For scanning all the keys, both the startKey and the endKey // can be supplied as empty strings. However, a full scan should be used judiciously for performance reasons. - // The returned VersionedResultsIterator contains results of type *VersionedRead. - GetStateRangeScanIterator(namespace driver.Namespace, startKey, endKey driver.PKey) (collections.Iterator[*R], error) + GetStateRangeScanIterator(namespace driver.Namespace, startKey, endKey driver.PKey) (collections.Iterator[*driver.UnversionedRead], error) // GetStateSetIterator returns an iterator that contains all the values for the passed keys. // The order is not respected. - GetStateSetIterator(ns driver.Namespace, keys ...driver.PKey) (collections.Iterator[*R], error) + GetStateSetIterator(ns driver.Namespace, keys ...driver.PKey) (collections.Iterator[*driver.UnversionedRead], error) // Close closes this persistence instance Close() error // BeginUpdate starts the session @@ -89,34 +75,12 @@ type BasePersistence[V any, R any] interface { Discard() error // Stats returns driver specific statistics of the datastore Stats() any -} -// UnversionedPersistence models a key-value storage place -type UnversionedPersistence interface { - BasePersistence[UnversionedValue, UnversionedRead] + NewWriteTransaction() (UnversionedWriteTransaction, error) } // VersionedPersistence models a versioned key-value storage place -type VersionedPersistence interface { - BasePersistence[VersionedValue, VersionedRead] - // GetStateMetadata gets the metadata and version for given namespace and key - GetStateMetadata(namespace driver.Namespace, key driver.PKey) (driver.Metadata, driver.RawVersion, error) - // SetStateMetadata sets the given metadata for the given namespace, key, and version - SetStateMetadata(namespace driver.Namespace, key driver.PKey, metadata driver.Metadata, version driver.RawVersion) error - // SetStateMetadatas sets the given metadata for the given namespace, keys, and version - SetStateMetadatas(ns driver.Namespace, kvs map[driver.PKey]driver.VersionedMetadataValue) map[driver.PKey]error -} - -type WriteTransaction interface { - // SetState sets the given value for the given namespace, key, and version - SetState(namespace driver.Namespace, key driver.PKey, value VersionedValue) error - // DeleteState deletes the given namespace and key - DeleteState(namespace driver.Namespace, key driver.PKey) error - // Commit commits the changes since BeginUpdate - Commit() error - // Discard discards the changes since BeginUpdate - Discard() error -} +type VersionedPersistence = UnversionedPersistence type UnversionedWriteTransaction interface { // SetState sets the given value for the given namespace, key @@ -129,18 +93,6 @@ type UnversionedWriteTransaction interface { Discard() error } -type TransactionalVersionedPersistence interface { - VersionedPersistence - - NewWriteTransaction() (WriteTransaction, error) -} - -type TransactionalUnversionedPersistence interface { - UnversionedPersistence - - NewWriteTransaction() (UnversionedWriteTransaction, error) -} - // Config provides access to the underlying configuration type Config interface { // IsSet checks to see if the key has been set in any of the data locations @@ -152,8 +104,8 @@ type Config interface { type NamedDriver = driver.NamedDriver[Driver] type Driver interface { - // NewTransactionalUnversioned returns a new TransactionalUnversionedPersistence for the passed data source and config - NewKVS(dataSourceName string, config Config) (TransactionalUnversionedPersistence, error) + // NewKVS returns a new UnversionedPersistence for the passed data source and config + NewKVS(dataSourceName string, config Config) (UnversionedPersistence, error) // NewBinding returns a new BindingPersistence for the passed data source and config NewBinding(dataSourceName string, config Config) (BindingPersistence, error) // NewSignerInfo returns a new SignerInfoPersistence for the passed data source and config @@ -194,7 +146,3 @@ type UnversionedNotifier interface { UnversionedPersistence Notifier } -type VersionedNotifier interface { - VersionedPersistence - Notifier -} diff --git a/platform/view/services/db/driver/memory/driver.go b/platform/view/services/db/driver/memory/driver.go index 931d11e90..432070073 100644 --- a/platform/view/services/db/driver/memory/driver.go +++ b/platform/view/services/db/driver/memory/driver.go @@ -10,9 +10,8 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/pkg/utils" driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/unversioned" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/sqlite" ) const ( @@ -41,38 +40,34 @@ func NewDriver() driver.NamedDriver { } } -func (d *Driver) NewKVS(string, driver.Config) (driver.TransactionalUnversionedPersistence, error) { - backend, err := sql.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sql.VersionedConstructors) - if err != nil { - return nil, err - } - return &unversioned.Transactional{TransactionalVersioned: backend}, nil +func (d *Driver) NewKVS(string, driver.Config) (driver.UnversionedPersistence, error) { + return common.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sqlite.NewUnversionedPersistence) } func (d *Driver) NewBinding(string, driver.Config) (driver.BindingPersistence, error) { - return sql.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sql.BindingConstructors) + return common.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sqlite.NewBindingPersistence) } func (d *Driver) NewSignerInfo(string, driver.Config) (driver.SignerInfoPersistence, error) { - return sql.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sql.SignerInfoConstructors) + return common.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sqlite.NewSignerInfoPersistence) } func (d *Driver) NewAuditInfo(string, driver.Config) (driver.AuditInfoPersistence, error) { - return sql.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sql.AuditInfoConstructors) + return common.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sqlite.NewAuditInfoPersistence) } func (d *Driver) NewEndorseTx(string, driver.Config) (driver.EndorseTxPersistence, error) { - return sql.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sql.EndorseTxConstructors) + return common.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sqlite.NewEndorseTxPersistence) } func (d *Driver) NewMetadata(string, driver.Config) (driver.MetadataPersistence, error) { - return sql.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sql.MetadataConstructors) + return common.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sqlite.NewMetadataPersistence) } func (d *Driver) NewEnvelope(string, driver.Config) (driver.EnvelopePersistence, error) { - return sql.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sql.EnvelopeConstructors) + return common.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sqlite.NewEnvelopePersistence) } func (d *Driver) NewVault(string, driver.Config) (driver.VaultPersistence, error) { - return sql.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sql.VaultConstructors) + return common.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), opts, sqlite.NewVaultPersistence) } diff --git a/platform/view/services/db/driver/notifier/persistence.go b/platform/view/services/db/driver/notifier/persistence.go index aa9b33149..9211ec3ff 100644 --- a/platform/view/services/db/driver/notifier/persistence.go +++ b/platform/view/services/db/driver/notifier/persistence.go @@ -8,25 +8,26 @@ package notifier import ( driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" ) // We treat update/inserts as the same, because we don't need the operation type. // Distinguishing the two cases for sqlite would require more logic. -func NewUnversioned[P driver.UnversionedPersistence](persistence P) *UnversionedPersistenceNotifier[P] { - return &UnversionedPersistenceNotifier[P]{ +func NewUnversioned(persistence driver.UnversionedPersistence) *UnversionedPersistenceNotifier { + return &UnversionedPersistenceNotifier{ Persistence: persistence, Notifier: NewNotifier(), } } -type UnversionedPersistenceNotifier[P driver.UnversionedPersistence] struct { - Persistence P +type UnversionedPersistenceNotifier struct { + Persistence driver.UnversionedPersistence *Notifier } -func (db *UnversionedPersistenceNotifier[P]) SetState(ns driver2.Namespace, key driver2.PKey, val driver2.RawValue) error { +func (db *UnversionedPersistenceNotifier) SetState(ns driver2.Namespace, key driver2.PKey, val driver2.RawValue) error { if err := db.Persistence.SetState(ns, key, val); err != nil { return err } @@ -38,7 +39,7 @@ func (db *UnversionedPersistenceNotifier[P]) SetState(ns driver2.Namespace, key return nil } -func (db *UnversionedPersistenceNotifier[P]) SetStates(ns driver2.Namespace, kvs map[driver2.PKey]driver2.RawValue) map[driver2.PKey]error { +func (db *UnversionedPersistenceNotifier) SetStates(ns driver2.Namespace, kvs map[driver2.PKey]driver2.RawValue) map[driver2.PKey]error { errs := db.Persistence.SetStates(ns, kvs) for key, val := range kvs { @@ -54,7 +55,7 @@ func (db *UnversionedPersistenceNotifier[P]) SetStates(ns driver2.Namespace, kvs return errs } -func (db *UnversionedPersistenceNotifier[P]) Commit() error { +func (db *UnversionedPersistenceNotifier) Commit() error { err := db.Persistence.Commit() if err != nil { return err @@ -63,7 +64,7 @@ func (db *UnversionedPersistenceNotifier[P]) Commit() error { return nil } -func (db *UnversionedPersistenceNotifier[P]) Discard() error { +func (db *UnversionedPersistenceNotifier) Discard() error { err := db.Persistence.Discard() if err != nil { return err @@ -72,7 +73,7 @@ func (db *UnversionedPersistenceNotifier[P]) Discard() error { return nil } -func (db *UnversionedPersistenceNotifier[P]) DeleteState(ns driver2.Namespace, key driver2.PKey) error { +func (db *UnversionedPersistenceNotifier) DeleteState(ns driver2.Namespace, key driver2.PKey) error { if err := db.Persistence.DeleteState(ns, key); err != nil { return err } @@ -80,7 +81,7 @@ func (db *UnversionedPersistenceNotifier[P]) DeleteState(ns driver2.Namespace, k return nil } -func (db *UnversionedPersistenceNotifier[P]) DeleteStates(namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { +func (db *UnversionedPersistenceNotifier) DeleteStates(namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { errs := db.Persistence.DeleteStates(namespace, keys...) for _, key := range keys { @@ -92,140 +93,34 @@ func (db *UnversionedPersistenceNotifier[P]) DeleteStates(namespace driver2.Name return errs } -func (db *UnversionedPersistenceNotifier[P]) GetState(namespace driver2.Namespace, key driver2.PKey) (driver2.RawValue, error) { +func (db *UnversionedPersistenceNotifier) GetState(namespace driver2.Namespace, key driver2.PKey) (driver2.RawValue, error) { return db.Persistence.GetState(namespace, key) } -func (db *UnversionedPersistenceNotifier[P]) GetStateRangeScanIterator(namespace driver2.Namespace, startKey, endKey driver2.PKey) (driver.UnversionedResultsIterator, error) { +func (db *UnversionedPersistenceNotifier) GetStateRangeScanIterator(namespace driver2.Namespace, startKey, endKey driver2.PKey) (collections.Iterator[*driver.UnversionedRead], error) { return db.Persistence.GetStateRangeScanIterator(namespace, startKey, endKey) } -func (db *UnversionedPersistenceNotifier[P]) GetStateSetIterator(ns driver2.Namespace, keys ...driver2.PKey) (driver.UnversionedResultsIterator, error) { +func (db *UnversionedPersistenceNotifier) GetStateSetIterator(ns driver2.Namespace, keys ...driver2.PKey) (collections.Iterator[*driver.UnversionedRead], error) { return db.Persistence.GetStateSetIterator(ns, keys...) } -func (db *UnversionedPersistenceNotifier[P]) Close() error { return db.Persistence.Close() } +func (db *UnversionedPersistenceNotifier) Close() error { return db.Persistence.Close() } -func (db *UnversionedPersistenceNotifier[P]) BeginUpdate() error { return db.Persistence.BeginUpdate() } +func (db *UnversionedPersistenceNotifier) BeginUpdate() error { return db.Persistence.BeginUpdate() } -func (db *UnversionedPersistenceNotifier[P]) Stats() any { +func (db *UnversionedPersistenceNotifier) Stats() any { return db.Persistence.Stats() } -func (db *UnversionedPersistenceNotifier[P]) Subscribe(callback driver.TriggerCallback) error { +func (db *UnversionedPersistenceNotifier) Subscribe(callback driver.TriggerCallback) error { return db.Notifier.Subscribe(callback) } -func (db *UnversionedPersistenceNotifier[P]) UnsubscribeAll() error { +func (db *UnversionedPersistenceNotifier) UnsubscribeAll() error { return db.Notifier.UnsubscribeAll() } - -func NewVersioned[P driver.VersionedPersistence](persistence P) *VersionedPersistenceNotifier[P] { - return &VersionedPersistenceNotifier[P]{ - Persistence: persistence, - Notifier: NewNotifier(), - } -} - -type VersionedPersistenceNotifier[P driver.VersionedPersistence] struct { - Persistence P - *Notifier -} - -func (db *VersionedPersistenceNotifier[P]) SetState(namespace driver2.Namespace, key driver2.PKey, value driver.VersionedValue) error { - if err := db.Persistence.SetState(namespace, key, value); err != nil { - return err - } - db.Notifier.EnqueueEvent(driver.Update, map[driver.ColumnKey]string{"ns": namespace, "pkey": key}) - return nil -} - -func (db *VersionedPersistenceNotifier[P]) SetStates(ns driver2.Namespace, kvs map[driver2.PKey]driver.VersionedValue) map[driver2.PKey]error { - errs := db.Persistence.SetStates(ns, kvs) - - for key := range kvs { - if _, ok := errs[key]; !ok { - db.Notifier.EnqueueEvent(driver.Update, map[driver.ColumnKey]string{"ns": ns, "pkey": key}) - } - } - - return errs -} - -func (db *VersionedPersistenceNotifier[P]) DeleteStates(namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { - errs := db.Persistence.DeleteStates(namespace, keys...) - - for _, key := range keys { - if _, ok := errs[key]; !ok { - db.Notifier.EnqueueEvent(driver.Delete, map[driver.ColumnKey]string{"ns": namespace, "pkey": key}) - } - } - - return errs -} - -func (db *VersionedPersistenceNotifier[P]) Commit() error { - err := db.Persistence.Commit() - if err != nil { - return err - } - db.Notifier.Commit() - return nil -} - -func (db *VersionedPersistenceNotifier[P]) Discard() error { - err := db.Persistence.Discard() - if err != nil { - return err - } - db.Notifier.Discard() - return nil -} - -func (db *VersionedPersistenceNotifier[P]) DeleteState(ns driver2.Namespace, key driver2.PKey) error { - if err := db.Persistence.DeleteState(ns, key); err != nil { - return err - } - db.Notifier.EnqueueEvent(driver.Delete, map[driver.ColumnKey]string{"ns": ns, "pkey": key}) - return nil -} - -func (db *VersionedPersistenceNotifier[P]) GetState(namespace driver2.Namespace, key driver2.PKey) (driver.VersionedValue, error) { - return db.Persistence.GetState(namespace, key) -} - -func (db *VersionedPersistenceNotifier[P]) GetStateMetadata(namespace driver2.Namespace, key driver2.PKey) (driver2.Metadata, driver2.RawVersion, error) { - return db.Persistence.GetStateMetadata(namespace, key) -} - -func (db *VersionedPersistenceNotifier[P]) SetStateMetadata(namespace driver2.Namespace, key driver2.PKey, metadata driver2.Metadata, version driver2.RawVersion) error { - return db.Persistence.SetStateMetadata(namespace, key, metadata, nil) -} - -func (db *VersionedPersistenceNotifier[P]) SetStateMetadatas(ns driver2.Namespace, kvs map[driver2.PKey]driver2.VersionedMetadataValue) map[driver2.PKey]error { - return db.Persistence.SetStateMetadatas(ns, kvs) -} - -func (db *VersionedPersistenceNotifier[P]) GetStateRangeScanIterator(namespace driver2.Namespace, startKey, endKey driver2.PKey) (driver.VersionedResultsIterator, error) { - return db.Persistence.GetStateRangeScanIterator(namespace, startKey, endKey) -} - -func (db *VersionedPersistenceNotifier[P]) GetStateSetIterator(ns driver2.Namespace, keys ...driver2.PKey) (driver.VersionedResultsIterator, error) { - return db.Persistence.GetStateSetIterator(ns, keys...) -} - -func (db *VersionedPersistenceNotifier[P]) Stats() any { - return db.Persistence.Stats() -} - -func (db *VersionedPersistenceNotifier[P]) Close() error { return db.Persistence.Close() } - -func (db *VersionedPersistenceNotifier[P]) BeginUpdate() error { return db.Persistence.BeginUpdate() } - -func (db *VersionedPersistenceNotifier[P]) Subscribe(callback driver.TriggerCallback) error { - return db.Notifier.Subscribe(callback) -} - -func (db *VersionedPersistenceNotifier[P]) UnsubscribeAll() error { - return db.Notifier.UnsubscribeAll() +func (db *UnversionedPersistenceNotifier) NewWriteTransaction() (driver.UnversionedWriteTransaction, error) { + // TODO: Fix notifier + return db.Persistence.NewWriteTransaction() } diff --git a/platform/view/services/db/driver/sql/common/base.go b/platform/view/services/db/driver/sql/common/base.go deleted file mode 100644 index ddb5d55aa..000000000 --- a/platform/view/services/db/driver/sql/common/base.go +++ /dev/null @@ -1,342 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package common - -import ( - "database/sql" - "fmt" - "strings" - "time" - - errors2 "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors" - driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" - "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/common" - "github.com/pkg/errors" - "golang.org/x/exp/slices" -) - -var logger = logging.MustGetLogger("view-sdk.db.driver.sql") - -type scannable interface { - Scan(dest ...any) error -} - -type readScanner[V any] interface { - // Columns returns a slice of the columns to be read into the V struct - Columns() []string - // ReadValue reads the columns in the order given above into a V struct - ReadValue(scannable) (V, error) -} - -type ValueScanner[V any] interface { - readScanner[V] - // WriteValue writes the values of the V struct in the order given by the Columns method - WriteValue(V) []any -} - -type BasePersistence[V any, R any] struct { - *common.BaseDB[*sql.Tx] - writeDB *sql.DB - readDB *sql.DB - table string - - readScanner readScanner[R] - ValueScanner ValueScanner[V] - errorWrapper driver.SQLErrorWrapper - ci Interpreter -} - -func NewBasePersistence[V any, R any](writeDB *sql.DB, readDB *sql.DB, table string, readScanner readScanner[R], valueScanner ValueScanner[V], errorWrapper driver.SQLErrorWrapper, ci Interpreter, newTransaction func() (*sql.Tx, error)) *BasePersistence[V, R] { - return &BasePersistence[V, R]{ - BaseDB: common.NewBaseDB(func() (*sql.Tx, error) { return newTransaction() }), - readDB: readDB, - writeDB: writeDB, - table: table, - readScanner: readScanner, - ValueScanner: valueScanner, - errorWrapper: errorWrapper, - ci: ci, - } -} - -func (db *BasePersistence[V, R]) GetStateRangeScanIterator(ns driver2.Namespace, startKey, endKey string) (collections.Iterator[*R], error) { - where, args := Where(db.ci.And( - db.ci.Cmp("ns", "=", ns), - db.ci.BetweenStrings("pkey", startKey, endKey), - )) - query := fmt.Sprintf("SELECT %s FROM %s %s ORDER BY pkey;", strings.Join(db.readScanner.Columns(), ", "), db.table, where) - logger.Debug(query, ns, startKey, endKey) - - rows, err := db.readDB.Query(query, args...) - if err != nil { - return nil, errors2.Wrapf(err, "query error: %s", query) - } - - return &readIterator[R]{txs: rows, scanner: db.readScanner}, nil -} - -func (db *BasePersistence[V, R]) GetState(namespace driver2.Namespace, key string) (V, error) { - where, args := Where(db.hasKey(namespace, key)) - query := fmt.Sprintf("SELECT %s FROM %s %s", strings.Join(db.ValueScanner.Columns(), ", "), db.table, where) - logger.Debug(query, args) - - row := db.readDB.QueryRow(query, args...) - if value, err := db.ValueScanner.ReadValue(row); err == nil { - return value, nil - } else if err == sql.ErrNoRows { - logger.Debugf("not found: [%s:%s]", namespace, key) - return value, nil - } else { - return value, errors2.Wrapf(err, "error querying db: %s", query) - } -} - -func (db *BasePersistence[V, R]) SetState(ns driver2.Namespace, pkey driver2.PKey, value V) error { - return db.SetStateWithTx(db.Txn, ns, pkey, value) -} - -func (db *BasePersistence[V, R]) SetStates(ns driver2.Namespace, kvs map[driver2.PKey]V) map[driver2.PKey]error { - errs := make(map[driver2.PKey]error) - for pkey, value := range kvs { - if err := db.SetState(ns, pkey, value); err != nil { - errs[pkey] = err - } - } - return errs -} - -func (db *BasePersistence[V, R]) GetStateSetIterator(ns driver2.Namespace, keys ...driver2.PKey) (collections.Iterator[*R], error) { - if len(keys) == 0 { - return collections.NewEmptyIterator[*R](), nil - } - where, args := Where(db.ci.And( - db.ci.Cmp("ns", "=", ns), - db.ci.InStrings("pkey", keys), - )) - query := fmt.Sprintf("SELECT %s FROM %s %s", strings.Join(db.readScanner.Columns(), ", "), db.table, where) - logger.Debug(query[:30] + "...") - - rows, err := db.readDB.Query(query, args...) - if err != nil { - return nil, errors2.Wrapf(err, "query error: %s", query) - } - - return &readIterator[R]{txs: rows, scanner: db.readScanner}, nil -} - -func (db *BasePersistence[V, R]) Close() error { - logger.Info("closing database") - - // TODO: what to do with db.Txn if it's not nil? - - err := db.writeDB.Close() - if err != nil { - return errors2.Wrapf(err, "could not close DB") - } - - return nil -} - -func (db *BasePersistence[V, R]) DeleteState(ns driver2.Namespace, key driver2.PKey) error { - return db.DeleteStateWithTx(db.Txn, ns, key) -} - -func (db *BasePersistence[V, R]) DeleteStateWithTx(tx *sql.Tx, ns driver2.Namespace, key driver2.PKey) error { - if errs := db.DeleteStatesWithTx(tx, ns, key); errs != nil { - return errs[key] - } - return nil -} - -func (db *BasePersistence[V, R]) DeleteStates(namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { - return db.DeleteStatesWithTx(db.Txn, namespace, keys...) -} - -func (db *BasePersistence[V, R]) DeleteStatesWithTx(tx *sql.Tx, namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { - if tx == nil { - panic("programming error, writing without ongoing update") - } - if namespace == "" { - return collections.RepeatValue(keys, errors.New("ns or key is empty")) - } - where, args := Where(db.hasKeys(namespace, keys)) - query := fmt.Sprintf("DELETE FROM %s %s", db.table, where) - logger.Debug(query, args) - _, err := tx.Exec(query, args...) - if err != nil { - errs := make(map[driver2.PKey]error) - for _, key := range keys { - errs[key] = errors.Wrapf(db.errorWrapper.WrapError(err), "could not delete val for key [%s]", key) - } - return errs - } - - return nil -} - -func (db *BasePersistence[V, R]) hasKeys(ns driver2.Namespace, pkeys []driver2.PKey) Condition { - return db.ci.And( - db.ci.Cmp("ns", "=", ns), - db.ci.InStrings("pkey", pkeys), - ) -} - -func (db *BasePersistence[V, R]) SetStateWithTx(tx *sql.Tx, ns driver2.Namespace, pkey string, value V) error { - if tx == nil { - panic("programming error, writing without ongoing update") - } - - keys := db.ValueScanner.Columns() - values := db.ValueScanner.WriteValue(value) - // Get rawVal - valIndex := slices.Index(keys, "val") - val := values[valIndex].([]byte) - if len(val) == 0 { - logger.Debugf("set key [%s:%s] to nil value, will be deleted instead", ns, pkey) - return db.DeleteState(ns, pkey) - } - - logger.Debugf("set state [%s,%s]", ns, pkey) - - // Overwrite rawVal - val = append([]byte(nil), val...) - values[valIndex] = val - - return db.UpsertStateWithTx(tx, ns, pkey, keys, values) -} - -func (db *BasePersistence[V, R]) UpsertStates(ns driver2.Namespace, valueKeys []string, vals map[driver2.PKey][]any) map[driver2.PKey]error { - errs := make(map[driver2.PKey]error) - for pkey, val := range vals { - if err := db.UpsertStateWithTx(db.Txn, ns, pkey, valueKeys, val); err != nil { - errs[pkey] = err - } - } - return errs -} - -func (db *BasePersistence[V, R]) UpsertStateWithTx(tx *sql.Tx, ns driver2.Namespace, pkey driver2.PKey, keys []string, values []any) error { - // Portable upsert - exists, err := db.exists(tx, ns, pkey) - if err != nil { - return err - } - - if exists { - sets := make([]string, len(keys)) - for i, key := range keys { - sets[i] = fmt.Sprintf("%s = $%d", key, i+1) - } - - cond := db.hasKey(ns, pkey) - offset := len(keys) + 1 - where, args := cond.ToString(&offset), cond.Params() - query := fmt.Sprintf("UPDATE %s SET %s WHERE %s", db.table, strings.Join(sets, ", "), where) - logger.Debug(query, args, len(values)) - - _, err := tx.Exec(query, append(values, args...)...) - if err != nil { - return errors2.Wrapf(db.errorWrapper.WrapError(err), "could not set val for key [%s]", pkey) - } - } else { - keys = append(keys, "ns", "pkey") - values = append(values, ns, pkey) - query := fmt.Sprintf("INSERT INTO %s (%s) VALUES %s", db.table, strings.Join(keys, ", "), GenerateParamSet(1, 1, len(keys))) - logger.Debug(query, ns, pkey, len(values)) - - _, err := tx.Exec(query, values...) - if err != nil { - return errors2.Wrapf(db.errorWrapper.WrapError(err), "could not insert [%s]", pkey) - } - } - logger.Debugf("set state [%s,%s], done", ns, pkey) - - return nil -} - -func (db *BasePersistence[V, R]) Exec(query string, args ...any) (sql.Result, error) { - return db.Txn.Exec(query, args...) -} - -func (db *BasePersistence[V, R]) Exists(ns driver2.Namespace, key driver2.PKey) (bool, error) { - if db.Txn == nil { - panic("programming error, writing without ongoing update") - } - return db.exists(db.Txn, ns, key) -} - -func (db *BasePersistence[V, R]) exists(tx *sql.Tx, ns driver2.Namespace, key driver2.PKey) (bool, error) { - var pkey string - where, args := Where(db.hasKey(ns, key)) - query := fmt.Sprintf("SELECT pkey FROM %s %s", db.table, where) - logger.Debug(query, args) - err := tx.QueryRow(query, args...).Scan(&pkey) - if err == sql.ErrNoRows { - return false, nil - } - if err != nil { - return false, errors2.Wrapf(err, "cannot check if key exists: %s", key) - } - return true, nil -} - -func (db *BasePersistence[V, R]) hasKey(ns driver2.Namespace, pkey string) Condition { - return db.ci.And( - db.ci.Cmp("ns", "=", ns), - db.ci.Cmp("pkey", "=", pkey), - ) -} - -func (db *BasePersistence[V, R]) InitSchema(query string) error { - return InitSchema(db.writeDB, query) -} - -func (db *BasePersistence[V, R]) TableName() string { - return db.table -} - -func (db *BasePersistence[V, R]) Stats() any { - if db.readDB != nil { - return db.readDB.Stats() - } - return nil -} - -type readIterator[V any] struct { - txs *sql.Rows - scanner readScanner[V] -} - -func (t *readIterator[V]) Close() { - t.txs.Close() -} - -func (t *readIterator[V]) Next() (*V, error) { - if !t.txs.Next() { - return nil, nil - } - - r, err := t.scanner.ReadValue(t.txs) - - return &r, err -} - -type SQLDriverType string - -type Opts struct { - Driver SQLDriverType - DataSource string - TablePrefix string - SkipCreateTable bool - SkipPragmas bool - MaxOpenConns int - MaxIdleConns *int - MaxIdleTime *time.Duration -} diff --git a/platform/view/services/db/driver/sql/common/binding.go b/platform/view/services/db/driver/sql/common/binding.go index 415ce2456..ddc8c4cdf 100644 --- a/platform/view/services/db/driver/sql/common/binding.go +++ b/platform/view/services/db/driver/sql/common/binding.go @@ -35,14 +35,13 @@ type BindingPersistence struct { func (db *BindingPersistence) GetLongTerm(ephemeral view.Identity) (view.Identity, error) { where, params := Where(db.ci.Cmp("ephemeral_hash", "=", ephemeral.UniqueID())) - result, err := QueryUnique[view.Identity](db.readDB, - fmt.Sprintf("SELECT long_term_id FROM %s %s", db.table, where), - params..., - ) + query := fmt.Sprintf("SELECT long_term_id FROM %s %s", db.table, where) + logger.Info(query, params) + result, err := QueryUnique[view.Identity](db.readDB, query, params...) if err != nil { return nil, errors.Wrapf(err, "failed getting wallet id for identity [%v]", ephemeral) } - logger.Debugf("found wallet id for identity [%v]: %v", ephemeral, result) + logger.Infof("found wallet id for identity [%v]: %v", ephemeral, result) return result, nil } func (db *BindingPersistence) HaveSameBinding(this, that view.Identity) (bool, error) { @@ -52,6 +51,7 @@ func (db *BindingPersistence) HaveSameBinding(this, that view.Identity) (bool, e if err != nil { return false, errors.Wrapf(err, "error querying db") } + defer rows.Close() longTermIds := make([]view.Identity, 0, 2) for rows.Next() { @@ -67,43 +67,6 @@ func (db *BindingPersistence) HaveSameBinding(this, that view.Identity) (bool, e return longTermIds[0].Equal(longTermIds[1]), nil } -func (db *BindingPersistence) PutBinding(ephemeral, longTerm view.Identity) error { - query := fmt.Sprintf( - "INSERT INTO %s (ephemeral_hash, long_term_id) "+ - "SELECT '%s', long_term_id FROM %s WHERE ephemeral_hash=$1", - db.table, ephemeral.UniqueID(), db.table) - - if result, err := db.writeDB.Exec(query, longTerm.UniqueID()); err != nil && errors.Is(db.errorWrapper.WrapError(err), driver.UniqueKeyViolation) { - logger.Warnf("Tuple [%s,%s] already in db. Skipping...", ephemeral, longTerm) - return nil - } else if err != nil { - return errors.Wrapf(err, "failed executing query [%s]", query) - } else if rowsAffected, err := result.RowsAffected(); err != nil { - return errors.Wrapf(err, "failed fetching affected rows for query: %s", query) - } else if rowsAffected > 1 { - panic("unexpected result") - } else if rowsAffected == 1 { - logger.Debugf("New binding registered [%s:%s]", ephemeral, longTerm) - return nil - } - - logger.Debugf("Long term ID not seen before. Registering it as long term...") - // query = fmt.Sprintf("INSERT INTO %s (ephemeral_hash, long_term_id) VALUES ($1, $2), ($3, $4)", db.table) - // if _, err = db.writeDB.Exec(query, longTerm.UniqueID(), longTerm, ephemeral.UniqueID(), longTerm); err != nil { - // return errors.Wrapf(err, "failed inserting long-term id and ephemeral id") - // } - query = fmt.Sprintf("INSERT INTO %s (ephemeral_hash, long_term_id) VALUES ($1, $2)", db.table) - if _, err := db.writeDB.Exec(query, longTerm.UniqueID(), longTerm); err != nil { - return errors.Wrapf(err, "failed inserting long-term id and ephemeral id") - } - query = fmt.Sprintf("INSERT INTO %s (ephemeral_hash, long_term_id) VALUES ($1, $2)", db.table) - if _, err := db.writeDB.Exec(query, ephemeral.UniqueID(), longTerm); err != nil { - return errors.Wrapf(err, "failed inserting long-term id and ephemeral id") - } - logger.Debugf("Long-term and ephemeral ids registered [%s,%s]", longTerm, ephemeral) - return nil - -} func (db *BindingPersistence) CreateSchema() error { return InitSchema(db.writeDB, fmt.Sprintf(` diff --git a/platform/view/services/db/driver/sql/common/signerinfo.go b/platform/view/services/db/driver/sql/common/signerinfo.go index 5d604c41f..67949a114 100644 --- a/platform/view/services/db/driver/sql/common/signerinfo.go +++ b/platform/view/services/db/driver/sql/common/signerinfo.go @@ -49,6 +49,7 @@ func (db *SignerInfoPersistence) FilterExistingSigners(ids ...view.Identity) ([] if err != nil { return nil, errors.Wrapf(err, "error querying db") } + defer func() { _ = rows.Close() }() existingSigners := make([]view.Identity, 0) for rows.Next() { diff --git a/platform/view/services/db/driver/sql/common/test_utils.go b/platform/view/services/db/driver/sql/common/test_utils.go index b04bb9df2..ef1193fca 100644 --- a/platform/view/services/db/driver/sql/common/test_utils.go +++ b/platform/view/services/db/driver/sql/common/test_utils.go @@ -17,21 +17,9 @@ import ( type provider[V any] func(name string) (V, error) func TestCases(t *testing.T, - versionedProvider provider[driver.TransactionalVersionedPersistence], unversionedProvider provider[driver.UnversionedPersistence], unversionedNotifierProvider provider[driver.UnversionedNotifier], - versionedNotifierProvider provider[driver.VersionedNotifier], - baseUnpacker func(p driver.UnversionedPersistence) *BasePersistence[driver.UnversionedValue, driver.UnversionedRead]) { - for _, c := range dbtest.Cases { - db, err := versionedProvider(c.Name) - if err != nil { - t.Fatal(err) - } - t.Run(c.Name, func(xt *testing.T) { - defer db.Close() - c.Fn(xt, db) - }) - } + baseUnpacker func(p driver.UnversionedPersistence) *UnversionedPersistence) { for _, c := range dbtest.UnversionedCases { un, err := unversionedProvider(c.Name) if err != nil { @@ -63,14 +51,4 @@ func TestCases(t *testing.T, c.Fn(xt, un) }) } - for _, c := range dbtest.VersionedNotifierCases { - un, err := versionedNotifierProvider(c.Name) - if err != nil { - t.Fatal(err) - } - t.Run(c.Name, func(xt *testing.T) { - defer un.Close() - c.Fn(xt, un) - }) - } } diff --git a/platform/view/services/db/driver/sql/common/unversioned.go b/platform/view/services/db/driver/sql/common/unversioned.go index 183e430f3..982435d33 100644 --- a/platform/view/services/db/driver/sql/common/unversioned.go +++ b/platform/view/services/db/driver/sql/common/unversioned.go @@ -9,53 +9,253 @@ package common import ( "database/sql" "fmt" + "time" + errors2 "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors" + driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/common" + "github.com/pkg/errors" ) +var logger = logging.MustGetLogger("view-sdk.db.driver.sql") + type UnversionedPersistence struct { - driver.BasePersistence[driver.UnversionedValue, driver.UnversionedRead] + *common.BaseDB[*sql.Tx] writeDB *sql.DB + readDB *sql.DB table string + + errorWrapper driver.SQLErrorWrapper + ci Interpreter } -func NewUnversionedPersistence(base driver.BasePersistence[driver.UnversionedValue, driver.UnversionedRead], writeDB *sql.DB, table string) *UnversionedPersistence { - return &UnversionedPersistence{BasePersistence: base, writeDB: writeDB, table: table} +func NewUnversionedPersistence(writeDB *sql.DB, readDB *sql.DB, table string, errorWrapper driver.SQLErrorWrapper, ci Interpreter) *UnversionedPersistence { + return &UnversionedPersistence{ + BaseDB: common.NewBaseDB(func() (*sql.Tx, error) { return writeDB.Begin() }), + readDB: readDB, + writeDB: writeDB, + table: table, + errorWrapper: errorWrapper, + ci: ci, + } } -func NewUnversionedReadScanner() *unversionedReadScanner { return &unversionedReadScanner{} } +func (db *UnversionedPersistence) GetStateRangeScanIterator(ns driver2.Namespace, startKey, endKey driver2.PKey) (collections.Iterator[*driver.UnversionedRead], error) { + where, args := Where(db.ci.And( + db.ci.Cmp("ns", "=", ns), + db.ci.BetweenStrings("pkey", startKey, endKey), + )) + query := fmt.Sprintf("SELECT pkey, val FROM %s %s ORDER BY pkey;", db.table, where) + logger.Debug(query, ns, startKey, endKey) -func NewUnversionedValueScanner() *unversionedValueScanner { return &unversionedValueScanner{} } + rows, err := db.readDB.Query(query, args...) + if err != nil { + return nil, errors2.Wrapf(err, "query error: %s", query) + } -func NewUnversioned(readDB *sql.DB, writeDB *sql.DB, table string, errorWrapper driver.SQLErrorWrapper, ci Interpreter) *UnversionedPersistence { - base := NewBasePersistence[driver.UnversionedValue, driver.UnversionedRead](writeDB, readDB, table, &unversionedReadScanner{}, &unversionedValueScanner{}, errorWrapper, ci, writeDB.Begin) - return NewUnversionedPersistence(base, base.writeDB, base.table) + return &readIterator{txs: rows}, nil } -type unversionedReadScanner struct{} +func (db *UnversionedPersistence) GetState(namespace driver2.Namespace, key driver2.PKey) (driver.UnversionedValue, error) { + where, args := Where(db.hasKey(namespace, key)) + query := fmt.Sprintf("SELECT val FROM %s %s", db.table, where) + logger.Debug(query, args) -func (s *unversionedReadScanner) Columns() []string { - return []string{"pkey", "val"} + return QueryUnique[driver.UnversionedValue](db.readDB, query, args...) } -func (s *unversionedReadScanner) ReadValue(txs scannable) (driver.UnversionedRead, error) { - var r driver.UnversionedRead - err := txs.Scan(&r.Key, &r.Raw) - return r, err + +func (db *UnversionedPersistence) SetState(ns driver2.Namespace, pkey driver2.PKey, value driver.UnversionedValue) error { + return db.SetStateWithTx(db.Txn, ns, pkey, value) +} + +func (db *UnversionedPersistence) SetStates(ns driver2.Namespace, kvs map[driver2.PKey]driver.UnversionedValue) map[driver2.PKey]error { + errs := make(map[driver2.PKey]error) + for pkey, value := range kvs { + if err := db.SetState(ns, pkey, value); err != nil { + errs[pkey] = err + } + } + return errs +} + +func (db *UnversionedPersistence) GetStateSetIterator(ns driver2.Namespace, keys ...driver2.PKey) (collections.Iterator[*driver.UnversionedRead], error) { + if len(keys) == 0 { + return collections.NewEmptyIterator[*driver.UnversionedRead](), nil + } + where, args := Where(db.ci.And( + db.ci.Cmp("ns", "=", ns), + db.ci.InStrings("pkey", keys), + )) + query := fmt.Sprintf("SELECT pkey, val FROM %s %s", db.table, where) + logger.Debug(query[:30] + "...") + + rows, err := db.readDB.Query(query, args...) + if err != nil { + return nil, errors2.Wrapf(err, "query error: %s", query) + } + + return &readIterator{txs: rows}, nil +} + +func (db *UnversionedPersistence) Close() error { + logger.Info("closing database") + + // TODO: what to do with db.Txn if it's not nil? + + err := db.writeDB.Close() + if err != nil { + return errors2.Wrapf(err, "could not close DB") + } + + return nil +} + +func (db *UnversionedPersistence) DeleteState(ns driver2.Namespace, key driver2.PKey) error { + return db.DeleteStateWithTx(db.Txn, ns, key) } -type unversionedValueScanner struct{} +func (db *UnversionedPersistence) DeleteStateWithTx(tx *sql.Tx, ns driver2.Namespace, key driver2.PKey) error { + if errs := db.DeleteStatesWithTx(tx, ns, key); errs != nil { + return errs[key] + } + return nil +} -func (s *unversionedValueScanner) Columns() []string { - return []string{"val"} +func (db *UnversionedPersistence) DeleteStates(namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { + return db.DeleteStatesWithTx(db.Txn, namespace, keys...) } -func (s *unversionedValueScanner) ReadValue(txs scannable) (driver.UnversionedValue, error) { - var r driver.UnversionedValue - err := txs.Scan(&r) - return r, err + +func (db *UnversionedPersistence) DeleteStatesWithTx(tx *sql.Tx, namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { + if tx == nil { + panic("programming error, writing without ongoing update") + } + if namespace == "" { + return collections.RepeatValue(keys, errors.New("ns or key is empty")) + } + where, args := Where(db.hasKeys(namespace, keys)) + query := fmt.Sprintf("DELETE FROM %s %s", db.table, where) + logger.Debug(query, args) + _, err := tx.Exec(query, args...) + if err != nil { + errs := make(map[driver2.PKey]error) + for _, key := range keys { + errs[key] = errors.Wrapf(db.errorWrapper.WrapError(err), "could not delete val for key [%s]", key) + } + return errs + } + + return nil +} + +func (db *UnversionedPersistence) hasKeys(ns driver2.Namespace, pkeys []driver2.PKey) Condition { + return db.ci.And( + db.ci.Cmp("ns", "=", ns), + db.ci.InStrings("pkey", pkeys), + ) +} + +func (db *UnversionedPersistence) SetStateWithTx(tx *sql.Tx, ns driver2.Namespace, pkey driver2.PKey, val driver.UnversionedValue) error { + if tx == nil { + panic("programming error, writing without ongoing update") + } + if len(val) == 0 { + logger.Debugf("set key [%s:%s] to nil value, will be deleted instead", ns, pkey) + return db.DeleteState(ns, pkey) + } + + logger.Debugf("set state [%s,%s]", ns, pkey) + + val = append([]byte(nil), val...) + + // Portable upsert + exists, err := db.exists(tx, ns, pkey) + if err != nil { + return err + } + + if exists { + + cond := db.hasKey(ns, pkey) + where, args := cond.ToString(CopyPtr(2)), cond.Params() + query := fmt.Sprintf("UPDATE %s SET val=$1 WHERE %s", db.table, where) + logger.Debug(query, val, args) + + _, err := tx.Exec(query, append([]any{val}, args...)...) + if err != nil { + return errors2.Wrapf(db.errorWrapper.WrapError(err), "could not set val for key [%s]", pkey) + } + } else { + query := fmt.Sprintf("INSERT INTO %s (ns, pkey, val) VALUES %s", db.table, GenerateParamSet(1, 1, 3)) + logger.Debug(query, ns, pkey, len(val)) + + _, err := tx.Exec(query, ns, pkey, val) + if err != nil { + return errors2.Wrapf(db.errorWrapper.WrapError(err), "could not insert [%s]", pkey) + } + } + logger.Debugf("set state [%s,%s], done", ns, pkey) + + return nil +} + +func (db *UnversionedPersistence) Exec(query string, args ...any) (sql.Result, error) { + return db.Txn.Exec(query, args...) } -func (s *unversionedValueScanner) WriteValue(value driver.UnversionedValue) []any { - return []any{value} +func (db *UnversionedPersistence) Exists(ns driver2.Namespace, key driver2.PKey) (bool, error) { + if db.Txn == nil { + panic("programming error, writing without ongoing update") + } + return db.exists(db.Txn, ns, key) +} + +func (db *UnversionedPersistence) exists(tx *sql.Tx, ns driver2.Namespace, key driver2.PKey) (bool, error) { + var pkey driver2.PKey + where, args := Where(db.hasKey(ns, key)) + query := fmt.Sprintf("SELECT pkey FROM %s %s", db.table, where) + logger.Debug(query, args) + err := tx.QueryRow(query, args...).Scan(&pkey) + if err == sql.ErrNoRows { + return false, nil + } + if err != nil { + return false, errors2.Wrapf(err, "cannot check if key exists: %s", key) + } + return true, nil +} + +func (db *UnversionedPersistence) hasKey(ns driver2.Namespace, pkey string) Condition { + return db.ci.And( + db.ci.Cmp("ns", "=", ns), + db.ci.Cmp("pkey", "=", pkey), + ) +} + +func (db *UnversionedPersistence) Stats() any { + if db.readDB != nil { + return db.readDB.Stats() + } + return nil +} + +type readIterator struct { + txs *sql.Rows +} + +func (t *readIterator) Close() { + t.txs.Close() +} + +func (t *readIterator) Next() (*driver.UnversionedRead, error) { + if !t.txs.Next() { + return nil, nil + } + var r driver.UnversionedRead + err := t.txs.Scan(&r.Key, &r.Raw) + return &r, err } func (db *UnversionedPersistence) CreateSchema() error { @@ -67,3 +267,64 @@ func (db *UnversionedPersistence) CreateSchema() error { PRIMARY KEY (pkey, ns) );`, db.table)) } + +func (db *UnversionedPersistence) NewWriteTransaction() (driver.UnversionedWriteTransaction, error) { + txn, err := db.writeDB.Begin() + if err != nil { + return nil, errors.WithMessagef(err, "failed to begin transaction") + } + + return NewWriteTransaction(txn, db), nil +} + +type versionedPersistence interface { + SetStateWithTx(tx *sql.Tx, ns driver2.Namespace, pkey string, value driver.UnversionedValue) error + DeleteStateWithTx(tx *sql.Tx, ns driver2.Namespace, key driver2.PKey) error +} + +func NewWriteTransaction(txn *sql.Tx, db versionedPersistence) *WriteTransaction { + return &WriteTransaction{txn: txn, db: db} +} + +type WriteTransaction struct { + txn *sql.Tx + db versionedPersistence +} + +func (w *WriteTransaction) SetState(namespace driver2.Namespace, key driver2.PKey, value driver.UnversionedValue) error { + return w.db.SetStateWithTx(w.txn, namespace, key, value) +} + +func (w *WriteTransaction) DeleteState(ns driver2.Namespace, key driver2.PKey) error { + return w.db.DeleteStateWithTx(w.txn, ns, key) +} + +func (w *WriteTransaction) Commit() error { + if err := w.txn.Commit(); err != nil { + return fmt.Errorf("could not commit transaction: %w", err) + } + w.txn = nil + return nil +} + +func (w *WriteTransaction) Discard() error { + if err := w.txn.Rollback(); err != nil { + logger.Infof("error rolling back (ignoring): %s", err.Error()) + return nil + } + w.txn = nil + return nil +} + +type SQLDriverType string + +type Opts struct { + Driver SQLDriverType + DataSource string + TablePrefix string + SkipCreateTable bool + SkipPragmas bool + MaxOpenConns int + MaxIdleConns *int + MaxIdleTime *time.Duration +} diff --git a/platform/view/services/db/driver/sql/common/utils.go b/platform/view/services/db/driver/sql/common/utils.go index c0d6434d4..90fe86d82 100644 --- a/platform/view/services/db/driver/sql/common/utils.go +++ b/platform/view/services/db/driver/sql/common/utils.go @@ -15,6 +15,7 @@ import ( "time" errors2 "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/pkg/errors" ) @@ -112,7 +113,7 @@ func InitSchema(db *sql.DB, schemas ...string) (err error) { } }() for _, schema := range schemas { - logger.Debug(schema) + logger.Info(schema) if _, err = tx.Exec(schema); err != nil { return errors2.Wrapf(err, "error creating schema: %s", schema) } @@ -187,3 +188,31 @@ func GenerateParamSet(offset int, rows, cols int) string { return sb.String() } + +type dbObject interface { + CreateSchema() error +} + +type PersistenceConstructor[V dbObject] func(Opts, string) (V, error) + +func NewPersistenceWithOpts[V dbObject](dataSourceName string, opts Opts, constructor PersistenceConstructor[V]) (V, error) { + nc, err := NewTableNameCreator(opts.TablePrefix) + if err != nil { + return utils.Zero[V](), err + } + + table, valid := nc.GetTableName(dataSourceName) + if !valid { + return utils.Zero[V](), fmt.Errorf("invalid table name [%s]: only letters and underscores allowed: %w", table, err) + } + p, err := constructor(opts, table) + if err != nil { + return utils.Zero[V](), err + } + if !opts.SkipCreateTable { + if err := p.CreateSchema(); err != nil { + return utils.Zero[V](), err + } + } + return p, nil +} diff --git a/platform/view/services/db/driver/sql/common/vault.go b/platform/view/services/db/driver/sql/common/vault.go index 3229236d7..3b5edc229 100644 --- a/platform/view/services/db/driver/sql/common/vault.go +++ b/platform/view/services/db/driver/sql/common/vault.go @@ -10,6 +10,7 @@ import ( "bytes" "context" "database/sql" + "encoding/gob" errors2 "errors" "fmt" @@ -124,7 +125,7 @@ func (db *VaultPersistence) GetStateMetadata(ctx context.Context, namespace driv return meta, kversion, err } -func (db *VaultPersistence) GetState(ctx context.Context, namespace driver.Namespace, key driver.PKey) (*driver.VersionedRead, error) { +func (db *VaultPersistence) GetState(ctx context.Context, namespace driver.Namespace, key driver.PKey) (*driver.VaultRead, error) { it, err := db.GetStates(ctx, namespace, key) if err != nil { return nil, err @@ -245,7 +246,7 @@ func (db *VaultPersistence) convertStateRows(writes driver.Writes, metaWrites dr for ns, write := range writes { metaWrite, ok := metaWrites[ns] if !ok { - metaWrite = map[driver.PKey]driver2.VersionedMetadataValue{} + metaWrite = map[driver.PKey]driver.VaultMetadataValue{} } for pkey, val := range write { var metadata = make([]byte, 0) @@ -281,7 +282,7 @@ func (db *VaultPersistence) convertStateRows(writes driver.Writes, metaWrites dr for ns, metaWrite := range metaWrites { write, ok := writes[ns] if !ok { - write = map[driver.PKey]driver2.VersionedValue{} + write = map[driver.PKey]driver.VaultValue{} } for pkey, metaVal := range metaWrite { if _, ok = write[pkey]; ok { @@ -381,8 +382,8 @@ func (it *TxStateIterator) Close() { _ = it.rows.Close() } -func (it *TxStateIterator) Next() (*driver.VersionedRead, error) { - var r driver.VersionedRead +func (it *TxStateIterator) Next() (*driver.VaultRead, error) { + var r driver.VaultRead if !it.rows.Next() { return nil, nil } @@ -396,3 +397,23 @@ func (it *TxStateIterator) Next() (*driver.VersionedRead, error) { } return &r, nil } + +func marshallMetadata(metadata map[string][]byte) (m []byte, err error) { + var buf bytes.Buffer + err = gob.NewEncoder(&buf).Encode(metadata) + if err != nil { + return + } + return buf.Bytes(), nil +} + +func unmarshalMetadata(input []byte) (m map[string][]byte, err error) { + if len(input) == 0 { + return + } + + buf := bytes.NewBuffer(input) + decoder := gob.NewDecoder(buf) + err = decoder.Decode(&m) + return +} diff --git a/platform/view/services/db/driver/sql/common/versioned.go b/platform/view/services/db/driver/sql/common/versioned.go deleted file mode 100644 index 8a4012aa2..000000000 --- a/platform/view/services/db/driver/sql/common/versioned.go +++ /dev/null @@ -1,240 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package common - -import ( - "bytes" - "database/sql" - "encoding/gob" - "fmt" - - "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors" - driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" -) - -func NewVersionedReadScanner() *versionedReadScanner { return &versionedReadScanner{} } - -func NewVersionedValueScanner() *versionedValueScanner { return &versionedValueScanner{} } - -func NewVersionedMetadataValueScanner() *versionedMetadataValueScanner { - return &versionedMetadataValueScanner{} -} - -type versionedReadScanner struct{} - -func (s *versionedReadScanner) Columns() []string { return []string{"pkey", "kversion", "val"} } - -func (s *versionedReadScanner) ReadValue(txs scannable) (driver.VersionedRead, error) { - var r driver.VersionedRead - err := txs.Scan(&r.Key, &r.Version, &r.Raw) - return r, err -} - -type versionedValueScanner struct{} - -func (s *versionedValueScanner) Columns() []string { return []string{"val", "kversion"} } - -func (s *versionedValueScanner) ReadValue(txs scannable) (driver.VersionedValue, error) { - var r driver.VersionedValue - err := txs.Scan(&r.Raw, &r.Version) - return r, err -} - -func (s *versionedValueScanner) WriteValue(value driver.VersionedValue) []any { - return []any{value.Raw, value.Version} -} - -type versionedMetadataValueScanner struct{} - -func (s *versionedMetadataValueScanner) Columns() []string { - return []string{"metadata", "kversion"} -} - -func (s *versionedMetadataValueScanner) ReadValue(txs scannable) (driver2.VersionedMetadataValue, error) { - var r driver2.VersionedMetadataValue - var metadata []byte - if err := txs.Scan(&metadata, &r.Version); err != nil { - return r, err - } else if meta, err := unmarshalMetadata(metadata); err != nil { - return r, fmt.Errorf("error decoding metadata: %w", err) - } else { - r.Metadata = meta - } - return r, nil -} - -func (s *versionedMetadataValueScanner) WriteValue(value driver2.VersionedMetadataValue) ([]any, error) { - metadata, err := marshallMetadata(value.Metadata) - if err != nil { - return nil, err - } - return []any{metadata, value.Version}, nil -} - -type basePersistence[V any, R any] interface { - driver.BasePersistence[driver.VersionedValue, driver.VersionedRead] - hasKey(ns driver2.Namespace, pkey string) Condition - Exists(namespace driver2.Namespace, key driver2.PKey) (bool, error) - Exec(query string, args ...any) (sql.Result, error) - SetStateWithTx(tx *sql.Tx, namespace driver2.Namespace, key string, value driver.VersionedValue) error - DeleteStateWithTx(tx *sql.Tx, ns driver2.Namespace, key driver2.PKey) error - UpsertStates(ns driver2.Namespace, valueKeys []string, vals map[driver2.PKey][]any) map[driver2.PKey]error -} - -type VersionedPersistence struct { - basePersistence[driver.VersionedValue, driver.VersionedRead] - table string - errorWrapper driver.SQLErrorWrapper - readDB *sql.DB - writeDB *sql.DB - metadataScanner *versionedMetadataValueScanner -} - -func NewVersionedPersistence(base basePersistence[driver.VersionedValue, driver.VersionedRead], table string, errorWrapper driver.SQLErrorWrapper, readDB *sql.DB, writeDB *sql.DB) *VersionedPersistence { - return &VersionedPersistence{basePersistence: base, table: table, errorWrapper: errorWrapper, readDB: readDB, writeDB: writeDB, metadataScanner: NewVersionedMetadataValueScanner()} -} - -func NewVersioned(readDB *sql.DB, writeDB *sql.DB, table string, errorWrapper driver.SQLErrorWrapper, ci Interpreter) *VersionedPersistence { - base := NewBasePersistence(writeDB, readDB, table, &versionedReadScanner{}, &versionedValueScanner{}, errorWrapper, ci, writeDB.Begin) - return NewVersionedPersistence(base, base.table, base.errorWrapper, base.readDB, base.writeDB) -} - -func (db *VersionedPersistence) SetStateMetadata(ns driver2.Namespace, key driver2.PKey, metadata driver2.Metadata, version driver2.RawVersion) error { - if len(metadata) == 0 { - return nil - } - return db.SetStateMetadatas( - ns, - map[driver2.PKey]driver2.VersionedMetadataValue{key: {Version: version, Metadata: metadata}}, - )[key] -} - -func (db *VersionedPersistence) SetStateMetadatas(ns driver2.Namespace, kvs map[driver2.PKey]driver2.VersionedMetadataValue) map[driver2.PKey]error { - errs := make(map[driver2.PKey]error) - vals := make(map[driver2.PKey][]any, len(kvs)) - for pkey, meta := range kvs { - if val, err := db.metadataScanner.WriteValue(meta); err != nil { - errs[pkey] = err - } else { - vals[pkey] = val - } - } - if len(errs) > 0 { - return errs - } - return db.UpsertStates(ns, db.metadataScanner.Columns(), vals) -} - -func (db *VersionedPersistence) GetStateMetadata(namespace driver2.Namespace, key driver2.PKey) (driver2.Metadata, driver2.RawVersion, error) { - var m []byte - var meta driver2.Metadata - var kversion driver2.RawVersion - - query := fmt.Sprintf("SELECT metadata, kversion FROM %s WHERE ns = $1 AND pkey = $2", db.table) - logger.Debug(query, namespace, key) - - row := db.readDB.QueryRow(query, namespace, key) - if err := row.Scan(&m, &kversion); err != nil { - if err == sql.ErrNoRows { - logger.Debugf("not found: [%s:%s]", namespace, key) - return meta, nil, nil - } - return meta, nil, fmt.Errorf("error querying db: %w", err) - } - meta, err := unmarshalMetadata(m) - if err != nil { - return meta, nil, fmt.Errorf("error decoding metadata: %w", err) - } - - return meta, kversion, err -} - -func (db *VersionedPersistence) CreateSchema() error { - return InitSchema(db.writeDB, fmt.Sprintf(` - CREATE TABLE IF NOT EXISTS %s ( - ns TEXT NOT NULL, - pkey TEXT NOT NULL, - val BYTEA NOT NULL DEFAULT '', - kversion BYTEA DEFAULT '', - metadata BYTEA NOT NULL DEFAULT '', - version INT NOT NULL DEFAULT 0, - PRIMARY KEY (pkey, ns) - );`, db.table)) -} - -func (db *VersionedPersistence) NewWriteTransaction() (driver.WriteTransaction, error) { - txn, err := db.writeDB.Begin() - if err != nil { - return nil, errors.WithMessagef(err, "failed to begin transaction") - } - - return NewWriteTransaction(txn, db), nil -} - -func (db *VersionedPersistence) Stats() any { - return db.basePersistence.Stats() -} - -type versionedPersistence interface { - SetStateWithTx(tx *sql.Tx, ns driver2.Namespace, pkey string, value driver.VersionedValue) error - DeleteStateWithTx(tx *sql.Tx, ns driver2.Namespace, key driver2.PKey) error -} - -func NewWriteTransaction(txn *sql.Tx, db versionedPersistence) *WriteTransaction { - return &WriteTransaction{txn: txn, db: db} -} - -type WriteTransaction struct { - txn *sql.Tx - db versionedPersistence -} - -func (w *WriteTransaction) SetState(namespace driver2.Namespace, key driver2.PKey, value driver.VersionedValue) error { - return w.db.SetStateWithTx(w.txn, namespace, key, value) -} - -func (w *WriteTransaction) DeleteState(ns driver2.Namespace, key driver2.PKey) error { - return w.db.DeleteStateWithTx(w.txn, ns, key) -} - -func (w *WriteTransaction) Commit() error { - if err := w.txn.Commit(); err != nil { - return fmt.Errorf("could not commit transaction: %w", err) - } - w.txn = nil - return nil -} - -func (w *WriteTransaction) Discard() error { - if err := w.txn.Rollback(); err != nil { - logger.Debugf("error rolling back (ignoring): %s", err.Error()) - return nil - } - w.txn = nil - return nil -} - -func marshallMetadata(metadata map[string][]byte) (m []byte, err error) { - var buf bytes.Buffer - err = gob.NewEncoder(&buf).Encode(metadata) - if err != nil { - return - } - return buf.Bytes(), nil -} - -func unmarshalMetadata(input []byte) (m map[string][]byte, err error) { - if len(input) == 0 { - return - } - - buf := bytes.NewBuffer(input) - decoder := gob.NewDecoder(buf) - err = decoder.Decode(&m) - return -} diff --git a/platform/view/services/db/driver/sql/driver.go b/platform/view/services/db/driver/sql/driver.go index 3aa6b48ab..f01d1d30e 100644 --- a/platform/view/services/db/driver/sql/driver.go +++ b/platform/view/services/db/driver/sql/driver.go @@ -16,7 +16,6 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/postgres" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/sqlite" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/unversioned" ) const ( @@ -42,22 +41,11 @@ type dbObject interface { CreateSchema() error } -type persistenceConstructor[V dbObject] func(common.Opts, string) (V, error) - -type transactionalVersionedPersistence interface { - driver.TransactionalVersionedPersistence +type unversionedPersistence interface { + driver.UnversionedPersistence dbObject } -var VersionedConstructors = map[common.SQLDriverType]persistenceConstructor[transactionalVersionedPersistence]{ - Postgres: func(o common.Opts, t string) (transactionalVersionedPersistence, error) { - return postgres.NewVersioned(o, t) - }, - SQLite: func(o common.Opts, t string) (transactionalVersionedPersistence, error) { - return sqlite.NewVersioned(o, t) - }, -} - type bindingPersistence interface { driver.BindingPersistence dbObject @@ -93,12 +81,21 @@ type vaultPersistence interface { dbObject } -var BindingConstructors = map[common.SQLDriverType]persistenceConstructor[bindingPersistence]{ +var UnversionedConstructors = map[common.SQLDriverType]common.PersistenceConstructor[unversionedPersistence]{ + Postgres: func(o common.Opts, t string) (unversionedPersistence, error) { + return postgres.NewUnversionedPersistence(o, t) + }, + SQLite: func(o common.Opts, t string) (unversionedPersistence, error) { + return sqlite.NewUnversionedPersistence(o, t) + }, +} + +var BindingConstructors = map[common.SQLDriverType]common.PersistenceConstructor[bindingPersistence]{ Postgres: func(o common.Opts, t string) (bindingPersistence, error) { return postgres.NewBindingPersistence(o, t) }, SQLite: func(o common.Opts, t string) (bindingPersistence, error) { return sqlite.NewBindingPersistence(o, t) }, } -var SignerInfoConstructors = map[common.SQLDriverType]persistenceConstructor[signerInfoPersistence]{ +var SignerInfoConstructors = map[common.SQLDriverType]common.PersistenceConstructor[signerInfoPersistence]{ Postgres: func(o common.Opts, t string) (signerInfoPersistence, error) { return postgres.NewSignerInfoPersistence(o, t) }, @@ -107,7 +104,7 @@ var SignerInfoConstructors = map[common.SQLDriverType]persistenceConstructor[sig }, } -var AuditInfoConstructors = map[common.SQLDriverType]persistenceConstructor[auditInfoPersistence]{ +var AuditInfoConstructors = map[common.SQLDriverType]common.PersistenceConstructor[auditInfoPersistence]{ Postgres: func(o common.Opts, t string) (auditInfoPersistence, error) { return postgres.NewAuditInfoPersistence(o, t) }, @@ -116,7 +113,7 @@ var AuditInfoConstructors = map[common.SQLDriverType]persistenceConstructor[audi }, } -var EndorseTxConstructors = map[common.SQLDriverType]persistenceConstructor[endorseTxPersistence]{ +var EndorseTxConstructors = map[common.SQLDriverType]common.PersistenceConstructor[endorseTxPersistence]{ Postgres: func(o common.Opts, t string) (endorseTxPersistence, error) { return postgres.NewEndorseTxPersistence(o, t) }, @@ -125,7 +122,7 @@ var EndorseTxConstructors = map[common.SQLDriverType]persistenceConstructor[endo }, } -var MetadataConstructors = map[common.SQLDriverType]persistenceConstructor[metadataPersistence]{ +var MetadataConstructors = map[common.SQLDriverType]common.PersistenceConstructor[metadataPersistence]{ Postgres: func(o common.Opts, t string) (metadataPersistence, error) { return postgres.NewMetadataPersistence(o, t) }, @@ -134,7 +131,7 @@ var MetadataConstructors = map[common.SQLDriverType]persistenceConstructor[metad }, } -var EnvelopeConstructors = map[common.SQLDriverType]persistenceConstructor[envelopePersistence]{ +var EnvelopeConstructors = map[common.SQLDriverType]common.PersistenceConstructor[envelopePersistence]{ Postgres: func(o common.Opts, t string) (envelopePersistence, error) { return postgres.NewEnvelopePersistence(o, t) }, @@ -143,7 +140,7 @@ var EnvelopeConstructors = map[common.SQLDriverType]persistenceConstructor[envel }, } -var VaultConstructors = map[common.SQLDriverType]persistenceConstructor[vaultPersistence]{ +var VaultConstructors = map[common.SQLDriverType]common.PersistenceConstructor[vaultPersistence]{ Postgres: func(o common.Opts, t string) (vaultPersistence, error) { return postgres.NewVaultPersistence(o, t) }, @@ -152,12 +149,8 @@ var VaultConstructors = map[common.SQLDriverType]persistenceConstructor[vaultPer }, } -func (d *Driver) NewKVS(dataSourceName string, config driver.Config) (driver.TransactionalUnversionedPersistence, error) { - backend, err := newPersistence(dataSourceName, config, VersionedConstructors) - if err != nil { - return nil, err - } - return &unversioned.Transactional{TransactionalVersioned: backend}, nil +func (d *Driver) NewKVS(dataSourceName string, config driver.Config) (driver.UnversionedPersistence, error) { + return newPersistence(dataSourceName, config, UnversionedConstructors) } func (d *Driver) NewBinding(dataSourceName string, config driver.Config) (driver.BindingPersistence, error) { @@ -188,40 +181,18 @@ func (d *Driver) NewVault(dataSourceName string, config driver.Config) (driver.V return newPersistence(dataSourceName, config, VaultConstructors) } -func newPersistence[V dbObject](dataSourceName string, config driver.Config, constructors map[common.SQLDriverType]persistenceConstructor[V]) (V, error) { +func newPersistence[V dbObject](dataSourceName string, config driver.Config, constructors map[common.SQLDriverType]common.PersistenceConstructor[V]) (V, error) { logger.Infof("opening new transactional database %s", dataSourceName) opts, err := getOps(config) if err != nil { return utils.Zero[V](), fmt.Errorf("failed getting options for datasource: %w", err) } - return NewPersistenceWithOpts(dataSourceName, opts, constructors) -} - -func NewPersistenceWithOpts[V dbObject](dataSourceName string, opts common.Opts, constructors map[common.SQLDriverType]persistenceConstructor[V]) (V, error) { - nc, err := common.NewTableNameCreator(opts.TablePrefix) - if err != nil { - return utils.Zero[V](), err - } - - table, valid := nc.GetTableName(dataSourceName) - if !valid { - return utils.Zero[V](), fmt.Errorf("invalid table name [%s]: only letters and underscores allowed: %w", table, err) - } c, ok := constructors[opts.Driver] if !ok { return utils.Zero[V](), fmt.Errorf("unknown driver: %s", opts.Driver) } - p, err := c(opts, table) - if err != nil { - return utils.Zero[V](), err - } - if !opts.SkipCreateTable { - if err := p.CreateSchema(); err != nil { - return utils.Zero[V](), err - } - } - return p, nil + return common.NewPersistenceWithOpts[V](dataSourceName, opts, c) } func getOps(config driver.Config) (common.Opts, error) { diff --git a/platform/view/services/db/driver/sql/postgres/base.go b/platform/view/services/db/driver/sql/postgres/base.go deleted file mode 100644 index 99ffdbbc3..000000000 --- a/platform/view/services/db/driver/sql/postgres/base.go +++ /dev/null @@ -1,136 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package postgres - -import ( - "database/sql" - "fmt" - "slices" - "strings" - - errors2 "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors" - "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" - driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" -) - -type BasePersistence[V any, R any] struct { - *common.BasePersistence[V, R] - - table string - ci common.Interpreter - errorWrapper driver2.SQLErrorWrapper -} - -func (db *BasePersistence[V, R]) SetState(ns driver.Namespace, pkey driver.PKey, value V) error { - return db.SetStateWithTx(db.Txn, ns, pkey, value) -} - -func (db *BasePersistence[V, R]) SetStates(ns driver.Namespace, kvs map[driver.PKey]V) map[driver.PKey]error { - return db.setStatesWithTx(db.Txn, ns, kvs) -} - -func (db *BasePersistence[V, R]) SetStateWithTx(tx *sql.Tx, ns driver.Namespace, pkey driver.PKey, value V) error { - if errs := db.setStatesWithTx(tx, ns, map[driver.PKey]V{pkey: value}); errs != nil { - return errs[encode(pkey)] - } - return nil -} - -func (db *BasePersistence[V, R]) DeleteState(namespace driver.Namespace, key driver.PKey) error { - return db.BasePersistence.DeleteState(namespace, encode(key)) -} - -func (db *BasePersistence[V, R]) DeleteStates(namespace driver.Namespace, keys ...driver.PKey) map[driver.PKey]error { - return db.BasePersistence.DeleteStates(namespace, encodeSlice(keys)...) -} - -func (db *BasePersistence[V, R]) Exists(ns driver.Namespace, key driver.PKey) (bool, error) { - return db.BasePersistence.Exists(ns, encode(key)) -} - -func (db *BasePersistence[V, R]) GetState(namespace driver.Namespace, key driver.PKey) (V, error) { - return db.BasePersistence.GetState(namespace, encode(key)) -} - -func (db *BasePersistence[V, R]) GetStateRangeScanIterator(ns driver.Namespace, startKey, endKey string) (collections.Iterator[*R], error) { - return db.BasePersistence.GetStateRangeScanIterator(ns, encode(startKey), encode(endKey)) -} - -func (db *BasePersistence[V, R]) GetStateSetIterator(ns driver.Namespace, keys ...driver.PKey) (collections.Iterator[*R], error) { - return db.BasePersistence.GetStateSetIterator(ns, encodeSlice(keys)...) -} - -func (db *BasePersistence[V, R]) setStatesWithTx(tx *sql.Tx, ns driver.Namespace, kvs map[driver.PKey]V) map[driver.PKey]error { - if tx == nil { - panic("programming error, writing without ongoing update") - } - keys := db.ValueScanner.Columns() - valIndex := slices.Index(keys, "val") - upserted := make(map[driver.PKey][]any, len(kvs)) - deleted := make([]driver.PKey, 0, len(kvs)) - for pkey, value := range kvs { - values := db.ValueScanner.WriteValue(value) - // Get rawVal - if val := values[valIndex].([]byte); len(val) == 0 { - logger.Debugf("set key [%s:%s] to nil value, will be deleted instead", ns, pkey) - deleted = append(deleted, pkey) - } else { - logger.Debugf("set state [%s,%s]", ns, pkey) - // Overwrite rawVal - val = append([]byte(nil), val...) - values[valIndex] = val - upserted[pkey] = values - } - } - - errs := make(map[driver.PKey]error) - if len(deleted) > 0 { - collections.CopyMap(errs, db.DeleteStatesWithTx(tx, ns, encodeSlice(deleted)...)) - } - if len(upserted) > 0 { - collections.CopyMap(errs, db.upsertStatesWithTx(tx, ns, keys, upserted)) - } - return errs -} - -func (db *BasePersistence[V, R]) UpsertStates(ns driver.Namespace, valueKeys []string, vals map[driver.PKey][]any) map[driver.PKey]error { - return db.upsertStatesWithTx(db.Txn, ns, valueKeys, vals) -} - -func (db *BasePersistence[V, R]) upsertStatesWithTx(tx *sql.Tx, ns driver.Namespace, valueKeys []string, vals map[driver.PKey][]any) map[driver.PKey]error { - vals = encodeMap(vals) - keys := append([]string{"ns", "pkey"}, valueKeys...) - query := fmt.Sprintf("INSERT INTO %s (%s) "+ - "VALUES %s "+ - "ON CONFLICT (ns, pkey) DO UPDATE "+ - "SET %s", - db.table, - strings.Join(keys, ", "), - common.CreateParamsMatrix(len(keys), len(vals), 1), - strings.Join(substitutions(valueKeys), ", ")) - - args := make([]any, 0, len(keys)*len(vals)) - for pkey, vals := range vals { - args = append(append(args, ns, pkey), vals...) - } - logger.Debug(query, args) - if _, err := tx.Exec(query, args...); err != nil { - return collections.RepeatValue(collections.Keys(vals), errors2.Wrapf(db.errorWrapper.WrapError(err), "could not upsert")) - } - return nil -} - -// TODO: AF Needs to be calculated only once -func substitutions(keys []string) []string { - subs := make([]string, len(keys)) - for i, key := range keys { - subs[i] = fmt.Sprintf("%s = excluded.%s", key, key) - } - return subs -} diff --git a/platform/view/services/db/driver/sql/postgres/bench_test.go b/platform/view/services/db/driver/sql/postgres/bench_test.go index 269fcb305..69cdd816c 100644 --- a/platform/view/services/db/driver/sql/postgres/bench_test.go +++ b/platform/view/services/db/driver/sql/postgres/bench_test.go @@ -11,7 +11,6 @@ import ( "time" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/dbtest" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/unversioned" ) func BenchmarkReadExistingPostgres(b *testing.B) { @@ -20,7 +19,7 @@ func BenchmarkReadExistingPostgres(b *testing.B) { b.Fatal(err) } defer terminate() - db, err := initPersistence(NewVersioned, pgConnStr, "benchmark", 50, 2, time.Minute) + db, err := initPersistence(NewUnversionedPersistence, pgConnStr, "benchmark", 50, 2, time.Minute) if err != nil { b.Fatal(err) } @@ -35,7 +34,7 @@ func BenchmarkReadNonExistingPostgres(b *testing.B) { b.Fatal(err) } defer terminate() - db, err := initPersistence(NewVersioned, pgConnStr, "benchmark", 50, 2, time.Minute) + db, err := initPersistence(NewUnversionedPersistence, pgConnStr, "benchmark", 50, 2, time.Minute) if err != nil { b.Fatal(err) } @@ -50,7 +49,7 @@ func BenchmarkWriteOnePostgres(b *testing.B) { b.Fatal(err) } defer terminate() - db, err := initPersistence(NewVersioned, pgConnStr, "benchmark", 50, 2, time.Minute) + db, err := initPersistence(NewUnversionedPersistence, pgConnStr, "benchmark", 50, 2, time.Minute) if err != nil { b.Fatal(err) } @@ -65,7 +64,7 @@ func BenchmarkWriteManyPostgres(b *testing.B) { b.Fatal(err) } defer terminate() - db, err := initPersistence(NewVersioned, pgConnStr, "benchmark", 50, 2, time.Minute) + db, err := initPersistence(NewUnversionedPersistence, pgConnStr, "benchmark", 50, 2, time.Minute) if err != nil { b.Fatal(err) } @@ -80,11 +79,10 @@ func BenchmarkWriteManyPostgresWithIdle(b *testing.B) { b.Fatal(err) } defer terminate() - p, err := initPersistence(NewVersioned, pgConnStr, "benchmark", 50, 50, time.Minute) + db, err := initPersistence(NewUnversionedPersistence, pgConnStr, "benchmark", 50, 50, time.Minute) if err != nil { b.Fatal(err) } - db := &unversioned.Transactional{TransactionalVersioned: p} defer db.Close() dbtest.WriteParallel(b, db) diff --git a/platform/view/services/db/driver/sql/postgres/binding.go b/platform/view/services/db/driver/sql/postgres/binding.go index 91b1cada1..135fad7bb 100644 --- a/platform/view/services/db/driver/sql/postgres/binding.go +++ b/platform/view/services/db/driver/sql/postgres/binding.go @@ -10,11 +10,17 @@ import ( "database/sql" "fmt" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" + "github.com/pkg/errors" ) type BindingPersistence struct { *common.BindingPersistence + table string + writeDB *sql.DB + errorWrapper driver.SQLErrorWrapper } func NewBindingPersistence(opts common.Opts, table string) (*BindingPersistence, error) { @@ -26,5 +32,38 @@ func NewBindingPersistence(opts common.Opts, table string) (*BindingPersistence, } func newBindingPersistence(readWriteDB *sql.DB, table string) *BindingPersistence { - return &BindingPersistence{BindingPersistence: common.NewBindingPersistence(readWriteDB, readWriteDB, table, &errorMapper{}, NewInterpreter())} + errorWrapper := &errorMapper{} + return &BindingPersistence{ + BindingPersistence: common.NewBindingPersistence(readWriteDB, readWriteDB, table, errorWrapper, NewInterpreter()), + table: table, + writeDB: readWriteDB, + errorWrapper: errorWrapper, + } +} +func (db *BindingPersistence) PutBinding(ephemeral, longTerm view.Identity) error { + logger.Debugf("Put binding for pair [%s:%s]", ephemeral.UniqueID(), longTerm.UniqueID()) + if lt, err := db.GetLongTerm(longTerm); err != nil { + return err + } else if lt != nil && !lt.IsNone() { + logger.Debugf("Replacing [%s] with long term [%s]", longTerm.UniqueID(), lt.UniqueID()) + longTerm = lt + } else { + logger.Infof("Id [%s] is an unregistered long term ID", longTerm.UniqueID()) + } + query := fmt.Sprintf(` + INSERT INTO %s (ephemeral_hash, long_term_id) + VALUES ($1, $2), ($3, $4) + ON CONFLICT DO NOTHING + `, db.table) + logger.Debug(query, ephemeral.UniqueID(), longTerm.UniqueID()) + _, err := db.writeDB.Exec(query, ephemeral.UniqueID(), longTerm, longTerm.UniqueID(), longTerm) + if err == nil { + logger.Debugf("Long-term and ephemeral ids registered [%s,%s]", longTerm, ephemeral) + return nil + } + if errors.Is(db.errorWrapper.WrapError(err), driver.UniqueKeyViolation) { + logger.Warnf("Tuple [%s,%s] already in db. Skipping...", ephemeral, longTerm) + return nil + } + return errors.Wrapf(err, "failed executing query [%s]", query) } diff --git a/platform/view/services/db/driver/sql/postgres/encode.go b/platform/view/services/db/driver/sql/postgres/encode.go index 570aca5c5..c24bd4046 100644 --- a/platform/view/services/db/driver/sql/postgres/encode.go +++ b/platform/view/services/db/driver/sql/postgres/encode.go @@ -16,10 +16,6 @@ import ( func identity(a string) (string, error) { return a, nil } -func decodeVersionedReadIterator(it collections.Iterator[*driver.VersionedRead], err error) (collections.Iterator[*driver.VersionedRead], error) { - return decodeIterator(it, err, decodeVersionedRead) -} - func decodeUnversionedReadIterator(it collections.Iterator[*driver2.UnversionedRead], err error) (collections.Iterator[*driver2.UnversionedRead], error) { return decodeIterator(it, err, decodeUnversionedRead) } @@ -39,21 +35,6 @@ func decode(s string) (string, error) { return string(b), err } -func decodeVersionedRead(v *driver.VersionedRead) (*driver.VersionedRead, error) { - if v == nil { - return nil, nil - } - key, err := decode(v.Key) - if err != nil { - return nil, err - } - return &driver.VersionedRead{ - Key: key, - Raw: v.Raw, - Version: v.Version, - }, nil -} - func decodeUnversionedRead(v *driver2.UnversionedRead) (*driver2.UnversionedRead, error) { if v == nil { return nil, nil diff --git a/platform/view/services/db/driver/sql/postgres/sql_test.go b/platform/view/services/db/driver/sql/postgres/sql_test.go index 5d56c0def..c35df598f 100644 --- a/platform/view/services/db/driver/sql/postgres/sql_test.go +++ b/platform/view/services/db/driver/sql/postgres/sql_test.go @@ -31,15 +31,11 @@ func TestPostgres(t *testing.T) { defer terminate() t.Log("postgres ready") - common2.TestCases(t, func(name string) (driver.TransactionalVersionedPersistence, error) { - return initPersistence(NewVersioned, pgConnStr, name, 50, 2, time.Minute) - }, func(name string) (driver.UnversionedPersistence, error) { - return initPersistence(NewUnversioned, pgConnStr, name, 0, 2, time.Minute) + common2.TestCases(t, func(name string) (driver.UnversionedPersistence, error) { + return initPersistence(NewUnversionedPersistence, pgConnStr, name, 0, 2, time.Minute) }, func(name string) (driver.UnversionedNotifier, error) { return initPersistence(NewUnversionedNotifier, pgConnStr, name, 0, 2, time.Minute) - }, func(name string) (driver.VersionedNotifier, error) { - return initPersistence(NewVersionedNotifier, pgConnStr, name, 50, 2, time.Minute) - }, func(p driver.UnversionedPersistence) *common2.BasePersistence[driver.UnversionedValue, driver.UnversionedRead] { - return p.(*UnversionedPersistence).BasePersistence.(*BasePersistence[driver.UnversionedValue, driver.UnversionedRead]).BasePersistence + }, func(p driver.UnversionedPersistence) *common2.UnversionedPersistence { + return p.(*UnversionedPersistence).UnversionedPersistence }) } diff --git a/platform/view/services/db/driver/sql/postgres/test_utils.go b/platform/view/services/db/driver/sql/postgres/test_utils.go index 044f199b9..960ee4b06 100644 --- a/platform/view/services/db/driver/sql/postgres/test_utils.go +++ b/platform/view/services/db/driver/sql/postgres/test_utils.go @@ -24,7 +24,6 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" common2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/unversioned" _ "modernc.org/sqlite" ) @@ -298,15 +297,11 @@ type TestDriver struct { ConnStr string } -func (t *TestDriver) NewKVS(dataSourceName string, config driver.Config) (driver.TransactionalUnversionedPersistence, error) { - p, err := initPersistence(NewVersioned, t.ConnStr, t.Name, 50, 10, time.Minute) - if err != nil { - return nil, err - } - return &unversioned.Transactional{TransactionalVersioned: p}, nil +func (t *TestDriver) NewKVS(string, driver.Config) (driver.UnversionedPersistence, error) { + return initPersistence(NewUnversionedPersistence, t.ConnStr, t.Name, 50, 10, time.Minute) } -func (t *TestDriver) NewBinding(dataSourceName string, config driver.Config) (driver.BindingPersistence, error) { +func (t *TestDriver) NewBinding(string, driver.Config) (driver.BindingPersistence, error) { return initPersistence(NewBindingPersistence, t.ConnStr, t.Name, 50, 10, time.Minute) } diff --git a/platform/view/services/db/driver/sql/postgres/unversioned.go b/platform/view/services/db/driver/sql/postgres/unversioned.go index 33c0d0fb3..fe1728eb2 100644 --- a/platform/view/services/db/driver/sql/postgres/unversioned.go +++ b/platform/view/services/db/driver/sql/postgres/unversioned.go @@ -10,50 +10,99 @@ import ( "database/sql" "fmt" - driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" + errors2 "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" + driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" ) type UnversionedPersistence struct { *common.UnversionedPersistence + + table string + ci common.Interpreter + errorWrapper driver2.SQLErrorWrapper } -func (p *UnversionedPersistence) SetState(namespace driver2.Namespace, key driver2.PKey, value driver.UnversionedValue) error { - return p.UnversionedPersistence.SetState(namespace, key, value) +func (db *UnversionedPersistence) SetState(ns driver.Namespace, pkey driver.PKey, value driver.UnversionedValue) error { + return db.SetStateWithTx(db.Txn, ns, pkey, value) } -func (p *UnversionedPersistence) SetStates(namespace driver2.Namespace, kvs map[driver2.PKey]driver.UnversionedValue) map[driver2.PKey]error { - return p.UnversionedPersistence.SetStates(namespace, kvs) +func (db *UnversionedPersistence) SetStates(ns driver.Namespace, kvs map[driver.PKey]driver.UnversionedValue) map[driver.PKey]error { + return db.setStatesWithTx(db.Txn, ns, kvs) } -func (p *UnversionedPersistence) GetState(namespace driver2.Namespace, key driver2.PKey) (driver.UnversionedValue, error) { - return p.UnversionedPersistence.GetState(namespace, key) +func (db *UnversionedPersistence) SetStateWithTx(tx *sql.Tx, ns driver.Namespace, pkey driver.PKey, value driver.UnversionedValue) error { + if errs := db.setStatesWithTx(tx, ns, map[driver.PKey]driver.UnversionedValue{pkey: value}); errs != nil { + return errs[encode(pkey)] + } + return nil } -func (p *UnversionedPersistence) DeleteState(namespace driver2.Namespace, key driver2.PKey) error { - return p.UnversionedPersistence.DeleteState(namespace, key) +func (db *UnversionedPersistence) GetStateRangeScanIterator(ns driver.Namespace, startKey, endKey string) (collections.Iterator[*driver.UnversionedRead], error) { + return decodeUnversionedReadIterator(db.UnversionedPersistence.GetStateRangeScanIterator(ns, encode(startKey), encode(endKey))) } -func (p *UnversionedPersistence) DeleteStates(namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { - return p.UnversionedPersistence.DeleteStates(namespace, keys...) +func (db *UnversionedPersistence) GetStateSetIterator(ns driver.Namespace, keys ...driver.PKey) (collections.Iterator[*driver.UnversionedRead], error) { + return decodeUnversionedReadIterator(db.UnversionedPersistence.GetStateSetIterator(ns, encodeSlice(keys)...)) } -func (p *UnversionedPersistence) GetStateRangeScanIterator(namespace driver2.Namespace, startKey, endKey driver2.PKey) (collections.Iterator[*driver.UnversionedRead], error) { - return decodeUnversionedReadIterator(p.UnversionedPersistence.GetStateRangeScanIterator(namespace, startKey, endKey)) +func (db *UnversionedPersistence) setStatesWithTx(tx *sql.Tx, ns driver.Namespace, kvs map[driver.PKey]driver.UnversionedValue) map[driver.PKey]error { + if tx == nil { + panic("programming error, writing without ongoing update") + } + + upserted := make(map[driver.PKey]driver.UnversionedValue, len(kvs)) + deleted := make([]driver.PKey, 0, len(kvs)) + for pkey, val := range kvs { + // Get rawVal + if len(val) == 0 { + logger.Debugf("set key [%s:%s] to nil value, will be deleted instead", ns, pkey) + deleted = append(deleted, pkey) + } else { + logger.Debugf("set state [%s,%s]", ns, pkey) + // Overwrite rawVal + upserted[pkey] = append([]byte(nil), val...) + } + } + + errs := make(map[driver.PKey]error) + if len(deleted) > 0 { + collections.CopyMap(errs, db.DeleteStatesWithTx(tx, ns, encodeSlice(deleted)...)) + } + if len(upserted) > 0 { + collections.CopyMap(errs, db.upsertStatesWithTx(tx, ns, encodeMap(upserted))) + } + return errs } -func (p *UnversionedPersistence) GetStateSetIterator(ns driver2.Namespace, keys ...driver2.PKey) (collections.Iterator[*driver.UnversionedRead], error) { - return decodeUnversionedReadIterator(p.UnversionedPersistence.GetStateSetIterator(ns, keys...)) +func (db *UnversionedPersistence) upsertStatesWithTx(tx *sql.Tx, ns driver.Namespace, vals map[driver.PKey]driver.UnversionedValue) map[driver.PKey]error { + + query := fmt.Sprintf("INSERT INTO %s (ns, pkey, val) "+ + "VALUES %s "+ + "ON CONFLICT (ns, pkey) DO UPDATE "+ + "SET val=excluded.val", + db.table, + common.CreateParamsMatrix(3, len(vals), 1)) + + args := make([]any, 0, 3*len(vals)) + for pkey, val := range vals { + args = append(args, ns, pkey, val) + } + logger.Debug(query, args) + if _, err := tx.Exec(query, args...); err != nil { + return collections.RepeatValue(collections.Keys(vals), errors2.Wrapf(db.errorWrapper.WrapError(err), "could not upsert")) + } + return nil } -func NewUnversioned(opts common.Opts, table string) (*UnversionedPersistence, error) { +func NewUnversionedPersistence(opts common.Opts, table string) (*UnversionedPersistence, error) { readWriteDB, err := OpenDB(opts.DataSource, opts.MaxOpenConns, opts.MaxIdleConns, opts.MaxIdleTime) if err != nil { return nil, fmt.Errorf("error opening db: %w", err) } - return newUnversioned(readWriteDB, table), nil + return newUnversionedPersistence(readWriteDB, table), nil } type unversionedPersistenceNotifier struct { @@ -62,7 +111,7 @@ type unversionedPersistenceNotifier struct { } func (db *unversionedPersistenceNotifier) CreateSchema() error { - if err := db.UnversionedPersistence.CreateSchema(); err != nil { + if err := db.UnversionedPersistence.UnversionedPersistence.CreateSchema(); err != nil { return err } return db.Notifier.CreateSchema() @@ -74,21 +123,18 @@ func NewUnversionedNotifier(opts common.Opts, table string) (*unversionedPersist return nil, fmt.Errorf("error opening db: %w", err) } return &unversionedPersistenceNotifier{ - UnversionedPersistence: newUnversioned(readWriteDB, table), + UnversionedPersistence: newUnversionedPersistence(readWriteDB, table), Notifier: NewNotifier(readWriteDB, table, opts.DataSource, AllOperations, primaryKey{"ns", identity}, primaryKey{"pkey", decode}), }, nil } -func newUnversioned(readWriteDB *sql.DB, table string) *UnversionedPersistence { +func newUnversionedPersistence(readWriteDB *sql.DB, table string) *UnversionedPersistence { ci := NewInterpreter() - em := &errorMapper{} - base := &BasePersistence[driver.UnversionedValue, driver.UnversionedRead]{ - BasePersistence: common.NewBasePersistence[driver.UnversionedValue, driver.UnversionedRead](readWriteDB, readWriteDB, table, common.NewUnversionedReadScanner(), common.NewUnversionedValueScanner(), em, ci, readWriteDB.Begin), - table: table, - ci: ci, - errorWrapper: em, - } + errorWrapper := &errorMapper{} return &UnversionedPersistence{ - UnversionedPersistence: common.NewUnversionedPersistence(base, readWriteDB, table), + UnversionedPersistence: common.NewUnversionedPersistence(readWriteDB, readWriteDB, table, errorWrapper, ci), + table: table, + ci: ci, + errorWrapper: errorWrapper, } } diff --git a/platform/view/services/db/driver/sql/postgres/versioned.go b/platform/view/services/db/driver/sql/postgres/versioned.go deleted file mode 100644 index 3303df409..000000000 --- a/platform/view/services/db/driver/sql/postgres/versioned.go +++ /dev/null @@ -1,151 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package postgres - -import ( - "database/sql" - "fmt" - - driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" - "github.com/pkg/errors" -) - -type VersionedPersistence struct { - p *common.VersionedPersistence - - writeDB *sql.DB -} - -func NewVersioned(opts common.Opts, table string) (*VersionedPersistence, error) { - readWriteDB, err := OpenDB(opts.DataSource, opts.MaxOpenConns, opts.MaxIdleConns, opts.MaxIdleTime) - if err != nil { - return nil, fmt.Errorf("error opening db: %w", err) - } - return newVersioned(readWriteDB, table), nil -} - -func (db *VersionedPersistence) SetState(namespace driver2.Namespace, key driver2.PKey, value driver.VersionedValue) error { - return db.p.SetState(namespace, key, value) -} - -func (db *VersionedPersistence) SetStates(namespace driver2.Namespace, kvs map[driver2.PKey]driver.VersionedValue) map[driver2.PKey]error { - return db.p.SetStates(namespace, kvs) -} - -func (db *VersionedPersistence) GetState(namespace driver2.Namespace, key driver2.PKey) (driver.VersionedValue, error) { - return db.p.GetState(namespace, key) -} - -func (db *VersionedPersistence) DeleteState(namespace driver2.Namespace, key driver2.PKey) error { - return db.p.DeleteState(namespace, key) -} - -func (db *VersionedPersistence) DeleteStates(namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { - return db.p.DeleteStates(namespace, encodeSlice(keys)...) -} - -func (db *VersionedPersistence) GetStateRangeScanIterator(namespace driver2.Namespace, startKey, endKey driver2.PKey) (collections.Iterator[*driver.VersionedRead], error) { - return decodeVersionedReadIterator(db.p.GetStateRangeScanIterator(namespace, startKey, endKey)) -} - -func (db *VersionedPersistence) GetStateSetIterator(ns driver2.Namespace, keys ...driver2.PKey) (collections.Iterator[*driver.VersionedRead], error) { - return decodeVersionedReadIterator(db.p.GetStateSetIterator(ns, keys...)) -} - -func (db *VersionedPersistence) Close() error { - return db.p.Close() -} - -func (db *VersionedPersistence) BeginUpdate() error { - return db.p.BeginUpdate() -} - -func (db *VersionedPersistence) Commit() error { - return db.p.Commit() -} - -func (db *VersionedPersistence) Discard() error { - return db.p.Discard() -} - -func (db *VersionedPersistence) GetStateMetadata(namespace driver2.Namespace, key driver2.PKey) (driver2.Metadata, driver2.RawVersion, error) { - return db.p.GetStateMetadata(namespace, encode(key)) -} - -func (db *VersionedPersistence) SetStateMetadata(namespace driver2.Namespace, key driver2.PKey, metadata driver2.Metadata, version driver2.RawVersion) error { - return db.p.SetStateMetadata(namespace, key, metadata, version) -} - -func (db *VersionedPersistence) SetStateMetadatas(ns driver2.Namespace, kvs map[driver2.PKey]driver2.VersionedMetadataValue) map[driver2.PKey]error { - return db.p.SetStateMetadatas(ns, kvs) -} - -func (db *VersionedPersistence) CreateSchema() error { - return db.p.CreateSchema() -} - -func (db *VersionedPersistence) SetStateWithTx(tx *sql.Tx, ns driver2.Namespace, pkey driver2.PKey, value driver.VersionedValue) error { - return db.p.SetStateWithTx(tx, ns, pkey, value) -} - -func (db *VersionedPersistence) DeleteStateWithTx(tx *sql.Tx, namespace driver2.Namespace, key driver2.PKey) error { - return db.p.DeleteStateWithTx(tx, namespace, key) -} - -func (db *VersionedPersistence) NewWriteTransaction() (driver.WriteTransaction, error) { - txn, err := db.writeDB.Begin() - if err != nil { - return nil, errors.WithMessagef(err, "failed to begin transaction") - } - - return common.NewWriteTransaction(txn, db), nil -} - -func (db *VersionedPersistence) Stats() any { - return db.p.Stats() -} - -type versionedPersistenceNotifier struct { - driver.VersionedPersistence - driver.Notifier -} - -func (db *versionedPersistenceNotifier) CreateSchema() error { - if err := db.VersionedPersistence.(*VersionedPersistence).CreateSchema(); err != nil { - return err - } - return db.Notifier.(*Notifier).CreateSchema() -} - -func NewVersionedNotifier(opts common.Opts, table string) (*versionedPersistenceNotifier, error) { - readWriteDB, err := OpenDB(opts.DataSource, opts.MaxOpenConns, opts.MaxIdleConns, opts.MaxIdleTime) - if err != nil { - return nil, fmt.Errorf("error opening db: %w", err) - } - return &versionedPersistenceNotifier{ - VersionedPersistence: newVersioned(readWriteDB, table), - Notifier: NewNotifier(readWriteDB, table, opts.DataSource, AllOperations, primaryKey{"ns", identity}, primaryKey{"pkey", decode}), - }, nil -} - -func newVersioned(readWriteDB *sql.DB, table string) *VersionedPersistence { - em := &errorMapper{} - ci := NewInterpreter() - base := &BasePersistence[driver.VersionedValue, driver.VersionedRead]{ - BasePersistence: common.NewBasePersistence(readWriteDB, readWriteDB, table, common.NewVersionedReadScanner(), common.NewVersionedValueScanner(), em, ci, readWriteDB.Begin), - table: table, - ci: ci, - errorWrapper: em, - } - return &VersionedPersistence{ - p: common.NewVersionedPersistence(base, table, em, readWriteDB, readWriteDB), - writeDB: readWriteDB, - } -} diff --git a/platform/view/services/db/driver/sql/sqlite/base.go b/platform/view/services/db/driver/sql/sqlite/base.go deleted file mode 100644 index 4a2ab84b9..000000000 --- a/platform/view/services/db/driver/sql/sqlite/base.go +++ /dev/null @@ -1,20 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package sqlite - -import ( - "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" -) - -type BasePersistence[V any, R any] struct { - *common.BasePersistence[V, R] -} - -func (db *BasePersistence[V, R]) SetStates(ns driver.Namespace, kvs map[driver.PKey]V) map[driver.PKey]error { - return db.BasePersistence.SetStates(ns, kvs) -} diff --git a/platform/view/services/db/driver/sql/sqlite/bench_test.go b/platform/view/services/db/driver/sql/sqlite/bench_test.go index 3ca9626f6..6737a7dd1 100644 --- a/platform/view/services/db/driver/sql/sqlite/bench_test.go +++ b/platform/view/services/db/driver/sql/sqlite/bench_test.go @@ -10,6 +10,7 @@ import ( "testing" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/dbtest" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/stretchr/testify/assert" ) @@ -45,8 +46,8 @@ func BenchmarkWriteManySqlite(b *testing.B) { dbtest.WriteMany(b, db) } -func newVersionedPersistence(dir string) (*VersionedPersistence, error) { - p, err := NewVersioned(dbOpts("benchmark", dir), "test") +func newVersionedPersistence(dir string) (driver.UnversionedPersistence, error) { + p, err := NewUnversionedPersistence(dbOpts("benchmark", dir), "test") if err != nil { return nil, err } diff --git a/platform/view/services/db/driver/sql/sqlite/binding.go b/platform/view/services/db/driver/sql/sqlite/binding.go index 864152e93..60f8c1d73 100644 --- a/platform/view/services/db/driver/sql/sqlite/binding.go +++ b/platform/view/services/db/driver/sql/sqlite/binding.go @@ -10,11 +10,17 @@ import ( "database/sql" "fmt" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" + "github.com/hyperledger-labs/fabric-smart-client/platform/view/view" + "github.com/pkg/errors" ) type BindingPersistence struct { *common.BindingPersistence + table string + writeDB *sql.DB + errorWrapper driver.SQLErrorWrapper } func NewBindingPersistence(opts common.Opts, table string) (*BindingPersistence, error) { @@ -26,5 +32,44 @@ func NewBindingPersistence(opts common.Opts, table string) (*BindingPersistence, } func newBindingPersistence(readDB, writeDB *sql.DB, table string) *BindingPersistence { - return &BindingPersistence{BindingPersistence: common.NewBindingPersistence(readDB, writeDB, table, &errorMapper{}, NewInterpreter())} + errorWrapper := &errorMapper{} + return &BindingPersistence{ + BindingPersistence: common.NewBindingPersistence(readDB, writeDB, table, errorWrapper, NewInterpreter()), + table: table, + writeDB: writeDB, + errorWrapper: errorWrapper, + } +} +func (db *BindingPersistence) PutBinding(ephemeral, longTerm view.Identity) error { + logger.Debugf("Put binding for pair [%s:%s]", ephemeral.UniqueID(), longTerm.UniqueID()) + if lt, err := db.GetLongTerm(longTerm); err != nil { + return err + } else if lt != nil && !lt.IsNone() { + logger.Debugf("Replacing [%s] with long term [%s]", longTerm.UniqueID(), lt.UniqueID()) + longTerm = lt + } else { + logger.Infof("Id [%s] is an unregistered long term ID", longTerm.UniqueID()) + } + query := fmt.Sprintf(` + BEGIN; + INSERT INTO %s (ephemeral_hash, long_term_id) + VALUES ($1, $2) + ON CONFLICT DO NOTHING; + INSERT INTO %s (ephemeral_hash, long_term_id) + VALUES ($3, $4) + ON CONFLICT DO NOTHING; + COMMIT; + `, db.table, db.table) + + logger.Debug(query, ephemeral.UniqueID(), longTerm.UniqueID()) + _, err := db.writeDB.Exec(query, ephemeral.UniqueID(), longTerm, longTerm.UniqueID(), longTerm) + if err == nil { + logger.Debugf("Long-term and ephemeral ids registered [%s,%s]", longTerm, ephemeral) + return nil + } + if errors.Is(db.errorWrapper.WrapError(err), driver.UniqueKeyViolation) { + logger.Warnf("Tuple [%s,%s] already in db. Skipping...", ephemeral, longTerm) + return nil + } + return errors.Wrapf(err, "failed executing query [%s]", query) } diff --git a/platform/view/services/db/driver/sql/sqlite/sql_test.go b/platform/view/services/db/driver/sql/sqlite/sql_test.go index bb70ede5b..99c11b9ef 100644 --- a/platform/view/services/db/driver/sql/sqlite/sql_test.go +++ b/platform/view/services/db/driver/sql/sqlite/sql_test.go @@ -17,28 +17,18 @@ import ( func TestSqlite(t *testing.T) { tempDir := t.TempDir() - common2.TestCases(t, func(name string) (driver.TransactionalVersionedPersistence, error) { - p, err := NewVersioned(dbOpts(name, tempDir), "test") - assert.NoError(t, err) - assert.NoError(t, p.CreateSchema()) - return p, nil - }, func(name string) (driver.UnversionedPersistence, error) { - p, err := NewUnversioned(dbOpts(name, tempDir), "test") + common2.TestCases(t, func(name string) (driver.UnversionedPersistence, error) { + p, err := NewUnversionedPersistence(dbOpts(name, tempDir), "test") assert.NoError(t, err) assert.NoError(t, p.CreateSchema()) return p, nil }, func(name string) (driver.UnversionedNotifier, error) { p, err := NewUnversionedNotifier(dbOpts(name, tempDir), "test") assert.NoError(t, err) - assert.NoError(t, p.Persistence.CreateSchema()) - return p, nil - }, func(name string) (driver.VersionedNotifier, error) { - p, err := NewVersionedNotifier(dbOpts(name, tempDir), "test") - assert.NoError(t, err) - assert.NoError(t, p.Persistence.CreateSchema()) + assert.NoError(t, p.Persistence.(*UnversionedPersistence).CreateSchema()) return p, nil - }, func(p driver.UnversionedPersistence) *common2.BasePersistence[driver.UnversionedValue, driver.UnversionedRead] { - return p.(*UnversionedPersistence).BasePersistence.(*BasePersistence[driver.UnversionedValue, driver.UnversionedRead]).BasePersistence + }, func(p driver.UnversionedPersistence) *common2.UnversionedPersistence { + return p.(*UnversionedPersistence).UnversionedPersistence }) } @@ -51,6 +41,6 @@ func TestGetSqliteDir(t *testing.T) { } func TestFolderDoesNotExistError(t *testing.T) { - _, err := NewUnversioned(dbOpts("folder-does-not-exist", "/this/folder/does/not/exist"), "test") + _, err := NewUnversionedPersistence(dbOpts("folder-does-not-exist", "/this/folder/does/not/exist"), "test") assert.Error(t, err, "error opening db: can't open sqlite database, does the folder exist?") } diff --git a/platform/view/services/db/driver/sql/sqlite/test_utils.go b/platform/view/services/db/driver/sql/sqlite/test_utils.go index 6569df3ee..34b4726f5 100644 --- a/platform/view/services/db/driver/sql/sqlite/test_utils.go +++ b/platform/view/services/db/driver/sql/sqlite/test_utils.go @@ -11,9 +11,9 @@ import ( "path" "time" + "github.com/hyperledger-labs/fabric-smart-client/pkg/utils" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" common2 "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/unversioned" ) type TestDriver struct { @@ -21,18 +21,11 @@ type TestDriver struct { TempDir string } -func (t *TestDriver) NewKVS(dataSourceName string, config driver.Config) (driver.TransactionalUnversionedPersistence, error) { - p, err := NewVersioned(dbOpts(t.Name, t.TempDir), "test") - if err != nil { - return nil, err - } - if err := p.CreateSchema(); err != nil { - return nil, err - } - return &unversioned.Transactional{TransactionalVersioned: p}, nil +func (t *TestDriver) NewKVS(string, driver.Config) (driver.UnversionedPersistence, error) { + return common2.NewPersistenceWithOpts(utils.GenerateUUIDOnlyLetters(), dbOpts(t.Name, t.TempDir), NewUnversionedPersistence) } -func (t *TestDriver) NewBinding(dataSourceName string, config driver.Config) (driver.BindingPersistence, error) { +func (t *TestDriver) NewBinding(string, driver.Config) (driver.BindingPersistence, error) { return NewBindingPersistence(dbOpts(t.Name, t.TempDir), "test") } diff --git a/platform/view/services/db/driver/sql/sqlite/unversioned.go b/platform/view/services/db/driver/sql/sqlite/unversioned.go index 688806290..200d41a97 100644 --- a/platform/view/services/db/driver/sql/sqlite/unversioned.go +++ b/platform/view/services/db/driver/sql/sqlite/unversioned.go @@ -19,7 +19,8 @@ type UnversionedPersistence struct { *common.UnversionedPersistence } -func NewUnversioned(opts common.Opts, table string) (*UnversionedPersistence, error) { +func NewUnversionedPersistence(opts common.Opts, table string) (*UnversionedPersistence, error) { + logger.Infof("Creating table... [%s]", table) readDB, writeDB, err := openDB(opts.DataSource, opts.MaxOpenConns, opts.MaxIdleConns, opts.MaxIdleTime, opts.SkipPragmas) if err != nil { return nil, fmt.Errorf("error opening db: %w", err) @@ -27,7 +28,7 @@ func NewUnversioned(opts common.Opts, table string) (*UnversionedPersistence, er return newUnversioned(readDB, writeDB, table), nil } -func NewUnversionedNotifier(opts common.Opts, table string) (*notifier.UnversionedPersistenceNotifier[*UnversionedPersistence], error) { +func NewUnversionedNotifier(opts common.Opts, table string) (*notifier.UnversionedPersistenceNotifier, error) { readDB, writeDB, err := openDB(opts.DataSource, opts.MaxOpenConns, opts.MaxIdleConns, opts.MaxIdleTime, opts.SkipPragmas) if err != nil { return nil, fmt.Errorf("error opening db: %w", err) @@ -36,10 +37,8 @@ func NewUnversionedNotifier(opts common.Opts, table string) (*notifier.Unversion } func newUnversioned(readDB, writeDB *sql.DB, table string) *UnversionedPersistence { - base := &BasePersistence[driver.UnversionedValue, driver.UnversionedRead]{ - BasePersistence: common.NewBasePersistence[driver.UnversionedValue, driver.UnversionedRead](writeDB, readDB, table, common.NewUnversionedReadScanner(), common.NewUnversionedValueScanner(), &errorMapper{}, NewInterpreter(), writeDB.Begin), - } + var wrapper driver.SQLErrorWrapper = &errorMapper{} return &UnversionedPersistence{ - UnversionedPersistence: common.NewUnversionedPersistence(base, writeDB, table), + UnversionedPersistence: common.NewUnversionedPersistence(writeDB, readDB, table, wrapper, NewInterpreter()), } } diff --git a/platform/view/services/db/driver/sql/sqlite/vault.go b/platform/view/services/db/driver/sql/sqlite/vault.go index f901cb3dc..f6e183966 100644 --- a/platform/view/services/db/driver/sql/sqlite/vault.go +++ b/platform/view/services/db/driver/sql/sqlite/vault.go @@ -13,6 +13,7 @@ import ( "strings" "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" "github.com/pkg/errors" "go.opentelemetry.io/otel/trace" @@ -95,7 +96,7 @@ func (db *VaultPersistence) Store(ctx context.Context, txIDs []driver.TxID, writ query := queryBuilder.String() - logger.Debug(query, params) + logger.Debug(query, txIDs, collections.Keys(writes)) if _, err := db.writeDB.Exec(query, params...); err != nil { return errors.Wrapf(err, "failed to store writes and metawrites for %d txs", len(txIDs)) } diff --git a/platform/view/services/db/driver/sql/sqlite/versioned.go b/platform/view/services/db/driver/sql/sqlite/versioned.go deleted file mode 100644 index 9c8d3b641..000000000 --- a/platform/view/services/db/driver/sql/sqlite/versioned.go +++ /dev/null @@ -1,45 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package sqlite - -import ( - "database/sql" - "fmt" - - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/notifier" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver/sql/common" -) - -type VersionedPersistence struct { - *common.VersionedPersistence -} - -func NewVersioned(opts common.Opts, table string) (*VersionedPersistence, error) { - readDB, writeDB, err := openDB(opts.DataSource, opts.MaxOpenConns, opts.MaxIdleConns, opts.MaxIdleTime, opts.SkipPragmas) - if err != nil { - return nil, fmt.Errorf("error opening db: %w", err) - } - return newVersioned(readDB, writeDB, table), nil -} - -func NewVersionedNotifier(opts common.Opts, table string) (*notifier.VersionedPersistenceNotifier[*VersionedPersistence], error) { - readDB, writeDB, err := openDB(opts.DataSource, opts.MaxOpenConns, opts.MaxIdleConns, opts.MaxIdleTime, opts.SkipPragmas) - if err != nil { - return nil, fmt.Errorf("error opening db: %w", err) - } - return notifier.NewVersioned(newVersioned(readDB, writeDB, table)), nil -} - -func newVersioned(readDB, writeDB *sql.DB, table string) *VersionedPersistence { - base := &BasePersistence[driver.VersionedValue, driver.VersionedRead]{ - BasePersistence: common.NewBasePersistence[driver.VersionedValue, driver.VersionedRead](writeDB, readDB, table, common.NewVersionedReadScanner(), common.NewVersionedValueScanner(), &errorMapper{}, NewInterpreter(), writeDB.Begin), - } - return &VersionedPersistence{ - VersionedPersistence: common.NewVersionedPersistence(base, table, &errorMapper{}, readDB, writeDB), - } -} diff --git a/platform/view/services/db/driver/unversioned/mocks/config.go b/platform/view/services/db/driver/unversioned/mocks/config.go deleted file mode 100644 index 3a3658565..000000000 --- a/platform/view/services/db/driver/unversioned/mocks/config.go +++ /dev/null @@ -1,183 +0,0 @@ -// Code generated by counterfeiter. DO NOT EDIT. -package mocks - -import ( - "sync" -) - -type Config struct { - IsSetStub func(string) bool - isSetMutex sync.RWMutex - isSetArgsForCall []struct { - arg1 string - } - isSetReturns struct { - result1 bool - } - isSetReturnsOnCall map[int]struct { - result1 bool - } - UnmarshalKeyStub func(string, interface{}) error - unmarshalKeyMutex sync.RWMutex - unmarshalKeyArgsForCall []struct { - arg1 string - arg2 interface{} - } - unmarshalKeyReturns struct { - result1 error - } - unmarshalKeyReturnsOnCall map[int]struct { - result1 error - } - invocations map[string][][]interface{} - invocationsMutex sync.RWMutex -} - -func (fake *Config) IsSet(arg1 string) bool { - fake.isSetMutex.Lock() - ret, specificReturn := fake.isSetReturnsOnCall[len(fake.isSetArgsForCall)] - fake.isSetArgsForCall = append(fake.isSetArgsForCall, struct { - arg1 string - }{arg1}) - stub := fake.IsSetStub - fakeReturns := fake.isSetReturns - fake.recordInvocation("IsSet", []interface{}{arg1}) - fake.isSetMutex.Unlock() - if stub != nil { - return stub(arg1) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *Config) IsSetCallCount() int { - fake.isSetMutex.RLock() - defer fake.isSetMutex.RUnlock() - return len(fake.isSetArgsForCall) -} - -func (fake *Config) IsSetCalls(stub func(string) bool) { - fake.isSetMutex.Lock() - defer fake.isSetMutex.Unlock() - fake.IsSetStub = stub -} - -func (fake *Config) IsSetArgsForCall(i int) string { - fake.isSetMutex.RLock() - defer fake.isSetMutex.RUnlock() - argsForCall := fake.isSetArgsForCall[i] - return argsForCall.arg1 -} - -func (fake *Config) IsSetReturns(result1 bool) { - fake.isSetMutex.Lock() - defer fake.isSetMutex.Unlock() - fake.IsSetStub = nil - fake.isSetReturns = struct { - result1 bool - }{result1} -} - -func (fake *Config) IsSetReturnsOnCall(i int, result1 bool) { - fake.isSetMutex.Lock() - defer fake.isSetMutex.Unlock() - fake.IsSetStub = nil - if fake.isSetReturnsOnCall == nil { - fake.isSetReturnsOnCall = make(map[int]struct { - result1 bool - }) - } - fake.isSetReturnsOnCall[i] = struct { - result1 bool - }{result1} -} - -func (fake *Config) UnmarshalKey(arg1 string, arg2 interface{}) error { - fake.unmarshalKeyMutex.Lock() - ret, specificReturn := fake.unmarshalKeyReturnsOnCall[len(fake.unmarshalKeyArgsForCall)] - fake.unmarshalKeyArgsForCall = append(fake.unmarshalKeyArgsForCall, struct { - arg1 string - arg2 interface{} - }{arg1, arg2}) - stub := fake.UnmarshalKeyStub - fakeReturns := fake.unmarshalKeyReturns - fake.recordInvocation("UnmarshalKey", []interface{}{arg1, arg2}) - fake.unmarshalKeyMutex.Unlock() - if stub != nil { - return stub(arg1, arg2) - } - if specificReturn { - return ret.result1 - } - return fakeReturns.result1 -} - -func (fake *Config) UnmarshalKeyCallCount() int { - fake.unmarshalKeyMutex.RLock() - defer fake.unmarshalKeyMutex.RUnlock() - return len(fake.unmarshalKeyArgsForCall) -} - -func (fake *Config) UnmarshalKeyCalls(stub func(string, interface{}) error) { - fake.unmarshalKeyMutex.Lock() - defer fake.unmarshalKeyMutex.Unlock() - fake.UnmarshalKeyStub = stub -} - -func (fake *Config) UnmarshalKeyArgsForCall(i int) (string, interface{}) { - fake.unmarshalKeyMutex.RLock() - defer fake.unmarshalKeyMutex.RUnlock() - argsForCall := fake.unmarshalKeyArgsForCall[i] - return argsForCall.arg1, argsForCall.arg2 -} - -func (fake *Config) UnmarshalKeyReturns(result1 error) { - fake.unmarshalKeyMutex.Lock() - defer fake.unmarshalKeyMutex.Unlock() - fake.UnmarshalKeyStub = nil - fake.unmarshalKeyReturns = struct { - result1 error - }{result1} -} - -func (fake *Config) UnmarshalKeyReturnsOnCall(i int, result1 error) { - fake.unmarshalKeyMutex.Lock() - defer fake.unmarshalKeyMutex.Unlock() - fake.UnmarshalKeyStub = nil - if fake.unmarshalKeyReturnsOnCall == nil { - fake.unmarshalKeyReturnsOnCall = make(map[int]struct { - result1 error - }) - } - fake.unmarshalKeyReturnsOnCall[i] = struct { - result1 error - }{result1} -} - -func (fake *Config) Invocations() map[string][][]interface{} { - fake.invocationsMutex.RLock() - defer fake.invocationsMutex.RUnlock() - fake.isSetMutex.RLock() - defer fake.isSetMutex.RUnlock() - fake.unmarshalKeyMutex.RLock() - defer fake.unmarshalKeyMutex.RUnlock() - copiedInvocations := map[string][][]interface{}{} - for key, value := range fake.invocations { - copiedInvocations[key] = value - } - return copiedInvocations -} - -func (fake *Config) recordInvocation(key string, args []interface{}) { - fake.invocationsMutex.Lock() - defer fake.invocationsMutex.Unlock() - if fake.invocations == nil { - fake.invocations = map[string][][]interface{}{} - } - if fake.invocations[key] == nil { - fake.invocations[key] = [][]interface{}{} - } - fake.invocations[key] = append(fake.invocations[key], args) -} diff --git a/platform/view/services/db/driver/unversioned/unversioned.go b/platform/view/services/db/driver/unversioned/unversioned.go deleted file mode 100644 index d0044a75b..000000000 --- a/platform/view/services/db/driver/unversioned/unversioned.go +++ /dev/null @@ -1,200 +0,0 @@ -/* -Copyright IBM Corp. All Rights Reserved. - -SPDX-License-Identifier: Apache-2.0 -*/ - -package unversioned - -import ( - driver2 "github.com/hyperledger-labs/fabric-smart-client/platform/common/driver" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" - "github.com/pkg/errors" -) - -type iterator struct { - itr driver.VersionedResultsIterator -} - -func (i *iterator) Next() (*driver.UnversionedRead, error) { - r, err := i.itr.Next() - if err != nil { - return nil, err - } - - if r == nil { - return nil, nil - } - - return &driver.UnversionedRead{ - Key: r.Key, - Raw: r.Raw, - }, nil -} - -func (i *iterator) Close() { - i.itr.Close() -} - -type Unversioned struct { - Versioned driver.VersionedPersistence -} - -func (db *Unversioned) SetState(namespace driver2.Namespace, key driver2.PKey, value driver2.RawValue) error { - return db.Versioned.SetState(namespace, key, driver.VersionedValue{Raw: value}) -} - -func (db *Unversioned) SetStates(namespace driver2.Namespace, kvs map[driver2.PKey]driver2.RawValue) map[driver2.PKey]error { - versioned := make(map[driver2.PKey]driver.VersionedValue, len(kvs)) - for k, v := range kvs { - versioned[k] = driver.VersionedValue{Raw: v} - } - return db.Versioned.SetStates(namespace, versioned) -} - -func (db *Unversioned) GetState(namespace driver2.Namespace, key driver2.PKey) (driver2.RawValue, error) { - vv, err := db.Versioned.GetState(namespace, key) - return vv.Raw, err -} - -func (db *Unversioned) DeleteState(namespace driver2.Namespace, key driver2.PKey) error { - return db.Versioned.DeleteState(namespace, key) -} - -func (db *Unversioned) DeleteStates(namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { - return db.Versioned.DeleteStates(namespace, keys...) -} - -func (db *Unversioned) GetStateRangeScanIterator(namespace driver2.Namespace, startKey, endKey driver2.PKey) (driver.UnversionedResultsIterator, error) { - vitr, err := db.Versioned.GetStateRangeScanIterator(namespace, startKey, endKey) - if err != nil { - return nil, err - } - - return &iterator{vitr}, nil -} - -func (db *Unversioned) GetStateSetIterator(ns driver2.Namespace, keys ...driver2.PKey) (driver.UnversionedResultsIterator, error) { - vitr, err := db.Versioned.GetStateSetIterator(ns, keys...) - if err != nil { - return nil, err - } - - return &iterator{vitr}, nil -} - -func (db *Unversioned) Close() error { - return db.Versioned.Close() -} - -func (db *Unversioned) BeginUpdate() error { - return db.Versioned.BeginUpdate() -} - -func (db *Unversioned) Commit() error { - return db.Versioned.Commit() -} - -func (db *Unversioned) Discard() error { - return db.Versioned.Discard() -} - -func (db *Unversioned) Stats() any { - return db.Versioned.Stats() -} - -type Transactional struct { - TransactionalVersioned driver.TransactionalVersionedPersistence -} - -func (t *Transactional) SetState(namespace driver2.Namespace, key driver2.PKey, value driver2.RawValue) error { - return t.TransactionalVersioned.SetState(namespace, key, driver.VersionedValue{Raw: value}) -} - -func (t *Transactional) SetStates(namespace driver2.Namespace, kvs map[driver2.PKey]driver2.RawValue) map[driver2.PKey]error { - versioned := make(map[driver2.PKey]driver.VersionedValue, len(kvs)) - for k, v := range kvs { - versioned[k] = driver.VersionedValue{Raw: v} - } - return t.TransactionalVersioned.SetStates(namespace, versioned) -} - -func (t *Transactional) GetState(namespace driver2.Namespace, key driver2.PKey) (driver2.RawValue, error) { - read, err := t.TransactionalVersioned.GetState(namespace, key) - if err != nil { - return nil, err - } - return read.Raw, nil -} - -func (t *Transactional) DeleteState(namespace driver2.Namespace, key driver2.PKey) error { - return t.TransactionalVersioned.DeleteState(namespace, key) -} - -func (t *Transactional) DeleteStates(namespace driver2.Namespace, keys ...driver2.PKey) map[driver2.PKey]error { - return t.TransactionalVersioned.DeleteStates(namespace, keys...) -} - -func (t *Transactional) GetStateRangeScanIterator(namespace driver2.Namespace, startKey driver2.PKey, endKey driver2.PKey) (driver.UnversionedResultsIterator, error) { - it, err := t.TransactionalVersioned.GetStateRangeScanIterator(namespace, startKey, endKey) - if err != nil { - return nil, err - } - return &iterator{itr: it}, nil -} - -func (t *Transactional) GetStateSetIterator(ns driver2.Namespace, keys ...driver2.PKey) (driver.UnversionedResultsIterator, error) { - it, err := t.TransactionalVersioned.GetStateSetIterator(ns, keys...) - if err != nil { - return nil, err - } - return &iterator{itr: it}, nil -} - -func (t *Transactional) Close() error { - return t.TransactionalVersioned.Close() -} - -func (t *Transactional) BeginUpdate() error { - return t.TransactionalVersioned.BeginUpdate() -} - -func (t *Transactional) Commit() error { - return t.TransactionalVersioned.Commit() -} - -func (t *Transactional) Discard() error { - return t.TransactionalVersioned.Discard() -} - -func (t *Transactional) NewWriteTransaction() (driver.UnversionedWriteTransaction, error) { - tx, err := t.TransactionalVersioned.NewWriteTransaction() - if err != nil { - return nil, errors.WithMessage(err, "failed to create new transaction") - } - return &WriteTransaction{WriteTransaction: tx}, nil -} - -func (t *Transactional) Stats() any { - return t.TransactionalVersioned.Stats() -} - -type WriteTransaction struct { - WriteTransaction driver.WriteTransaction -} - -func (w *WriteTransaction) SetState(namespace driver2.Namespace, key string, value []byte) error { - return w.WriteTransaction.SetState(namespace, key, driver.VersionedValue{Raw: value}) -} - -func (w *WriteTransaction) DeleteState(namespace driver2.Namespace, key string) error { - return w.WriteTransaction.DeleteState(namespace, key) -} - -func (w *WriteTransaction) Commit() error { - return w.WriteTransaction.Commit() -} - -func (w *WriteTransaction) Discard() error { - return w.WriteTransaction.Discard() -} diff --git a/platform/view/services/db/keys/utils.go b/platform/view/services/db/keys/utils.go index 7f876e3f9..f42e274d4 100644 --- a/platform/view/services/db/keys/utils.go +++ b/platform/view/services/db/keys/utils.go @@ -40,10 +40,10 @@ func ValidateNs(ns string) error { type DummyVersionedIterator struct { idx int - Items []*driver.VersionedRead + Items []*driver.UnversionedRead } -func (r *DummyVersionedIterator) Next() (*driver.VersionedRead, error) { +func (r *DummyVersionedIterator) Next() (*driver.UnversionedRead, error) { if r.Items == nil || r.idx == len(r.Items) { return nil, nil } diff --git a/platform/view/services/kvs/kvs.go b/platform/view/services/kvs/kvs.go index d874d2f2f..fc19a1625 100644 --- a/platform/view/services/kvs/kvs.go +++ b/platform/view/services/kvs/kvs.go @@ -13,10 +13,10 @@ import ( "github.com/hyperledger-labs/fabric-smart-client/pkg/utils" "github.com/hyperledger-labs/fabric-smart-client/pkg/utils/errors" "github.com/hyperledger-labs/fabric-smart-client/platform/common/services/logging" + "github.com/hyperledger-labs/fabric-smart-client/platform/common/utils/collections" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/cache/secondcache" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/storage" - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/storage/db" "go.uber.org/zap/zapcore" ) @@ -57,7 +57,7 @@ type Iterator interface { type KVS struct { namespace string - store driver.TransactionalUnversionedPersistence + store driver.UnversionedPersistence putMutex sync.RWMutex cache cache @@ -65,11 +65,10 @@ type KVS struct { // NewWithConfig returns a new KVS instance for the passed namespace using the passed driver and config provider func NewWithConfig(dbDriver driver.Driver, namespace string, cp ConfigProvider) (*KVS, error) { - d, err := dbDriver.NewKVS(namespace, storage.NewPrefixConfig(cp, persistenceOptsConfigKey)) + persistence, err := dbDriver.NewKVS(namespace, storage.NewPrefixConfig(cp, persistenceOptsConfigKey)) if err != nil { return nil, errors.Wrapf(err, "failed opening datasource [%s]", namespace) } - persistence := &db.TransactionalUnversionedPersistence{TransactionalUnversionedPersistence: d} cacheSize, err := cacheSizeFromConfig(cp) if err != nil { @@ -175,6 +174,7 @@ func (o *KVS) Put(id string, state interface{}) error { } return false, errors.Wrapf(err, "committing value for id [%s] failed", id) } + logger.Infof("committed tx for id [%s]", id) return true, nil }); err != nil { return err @@ -275,7 +275,7 @@ func (o *KVS) Stop() { } type it struct { - ri driver.UnversionedResultsIterator + ri collections.Iterator[*driver.UnversionedRead] next *driver.UnversionedRead } diff --git a/platform/view/services/storage/db/db.go b/platform/view/services/storage/db/db.go index 9faede148..14ad1dff7 100644 --- a/platform/view/services/storage/db/db.go +++ b/platform/view/services/storage/db/db.go @@ -9,8 +9,6 @@ package db import ( "regexp" "strings" - - "github.com/hyperledger-labs/fabric-smart-client/platform/view/services/db/driver" ) // Config models the DB configuration @@ -21,10 +19,6 @@ type Config interface { UnmarshalKey(key string, rawVal interface{}) error } -type TransactionalUnversionedPersistence struct { - driver.TransactionalUnversionedPersistence -} - var validName = regexp.MustCompile(`^[a-zA-Z_]+$`) // Thread safe var replacers = []*replacer{ newReplacer("_", "__"),