From 3ac63584b6e9e781e97a64746d52a2dd1ebc72b0 Mon Sep 17 00:00:00 2001 From: manish Date: Mon, 9 Oct 2017 18:02:16 -0400 Subject: [PATCH] [FAB-6552] Block-to-live policy for pvtdata This CR introduces a BTL policy based on configuration in the core.yaml file Change-Id: Icef38b180d8a1f1c3336a59cca2f63dfbdab3964 Signed-off-by: manish --- core/ledger/pvtdatapolicy/btlpolicy.go | 94 +++++++++++++++++++++ core/ledger/pvtdatapolicy/btlpolicy_test.go | 34 ++++++++ 2 files changed, 128 insertions(+) create mode 100644 core/ledger/pvtdatapolicy/btlpolicy.go create mode 100644 core/ledger/pvtdatapolicy/btlpolicy_test.go diff --git a/core/ledger/pvtdatapolicy/btlpolicy.go b/core/ledger/pvtdatapolicy/btlpolicy.go new file mode 100644 index 00000000000..d9f93160b21 --- /dev/null +++ b/core/ledger/pvtdatapolicy/btlpolicy.go @@ -0,0 +1,94 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package pvtdatapolicy + +import ( + "math" + "sync" + + "github.com/spf13/viper" +) + +var defaultBLT uint64 = math.MaxUint64 +var btlPolicyMap map[string]BTLPolicy +var lock = &sync.Mutex{} + +func init() { + btlPolicyMap = make(map[string]BTLPolicy) +} + +// BTLPolicy BlockToLive policy for the pvt data +type BTLPolicy interface { + // init initializes BTLPolicy for the given channelName + init(channelName string) error + // GetBTL returns BlockToLive for a given namespace and collection + GetBTL(ns string, coll string) uint64 + // GetExpiringBlock returns the block number by which the pvtdata for given namespace,collection, and committingBlock should expire + GetExpiringBlock(namesapce string, collection string, committingBlock uint64) uint64 +} + +// GetBTLPolicy constructs (if not already done) and returns the BTLPolicy for the given channel +func GetBTLPolicy(channelName string) (BTLPolicy, error) { + lock.Lock() + defer lock.Unlock() + m := btlPolicyMap[channelName] + if m == nil { + m = &configBasedBTLPolicy{} + m.init(channelName) + btlPolicyMap[channelName] = m + } + return m, nil +} + +// configBasedBTLPolicy implements interface BTLPolicy. +// This implementation loads the BTL policy from configuration. This implementation is meant as a stop gap arrangement +// until the config transaction framework is in place. This is becasue, the BTL policy should be consistent across peer +// and should not change across different replays of transactions in the chain and hence it should be set via a config +// transaction only. Later, another implementation should be provided that loads the BTL policy from config transactions +type configBasedBTLPolicy struct { + channelName string + cache map[btlkey]uint64 +} + +type btlkey struct { + ns string + coll string +} + +// Init implements corresponding function in interface `BTLPolicyMgr` +func (m *configBasedBTLPolicy) init(channelName string) error { + m.channelName = channelName + m.cache = make(map[btlkey]uint64) + return nil +} + +// GetBTL implements corresponding function in interface `BTLPolicyMgr` +func (m *configBasedBTLPolicy) GetBTL(namesapce string, collection string) uint64 { + var btl uint64 + var ok bool + key := btlkey{namesapce, collection} + btl, ok = m.cache[key] + if !ok { + btlConfigured := viper.GetInt("ledger.pvtdata.btlpolicy." + m.channelName + "." + namesapce + "." + collection) + if btlConfigured > 0 { + btl = uint64(btlConfigured) + } else { + btl = defaultBLT + } + m.cache[key] = btl + } + return btl +} + +func (m *configBasedBTLPolicy) GetExpiringBlock(namesapce string, collection string, committingBlock uint64) uint64 { + btl := m.GetBTL(namesapce, collection) + expiryBlk := committingBlock + btl + uint64(1) + if expiryBlk <= committingBlock { // committingBlk + btl overflows uint64-max + expiryBlk = math.MaxUint64 + } + return expiryBlk +} diff --git a/core/ledger/pvtdatapolicy/btlpolicy_test.go b/core/ledger/pvtdatapolicy/btlpolicy_test.go new file mode 100644 index 00000000000..fea84ab33b4 --- /dev/null +++ b/core/ledger/pvtdatapolicy/btlpolicy_test.go @@ -0,0 +1,34 @@ +/* +Copyright IBM Corp. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 +*/ + +package pvtdatapolicy + +import ( + "math" + "testing" + + "github.com/spf13/viper" + "github.com/stretchr/testify/assert" +) + +func TestBTLPolicy(t *testing.T) { + viper.Set("ledger.pvtdata.btlpolicy.ch1.ns1.coll1", 1) + viper.Set("ledger.pvtdata.btlpolicy.ch1.ns2.coll2", 2) + viper.Set("ledger.pvtdata.btlpolicy.ch2.ns2.coll2", 3) + viper.Set("ledger.pvtdata.btlpolicy.ch2.ns3.coll4", 4) + + btlCh1, _ := GetBTLPolicy("ch1") + btlCh2, _ := GetBTLPolicy("ch2") + + assert.Equal(t, uint64(1), btlCh1.GetBTL("ns1", "coll1")) + assert.Equal(t, uint64(4), btlCh2.GetBTL("ns3", "coll4")) + assert.Equal(t, defaultBLT, btlCh2.GetBTL("ns1", "coll5")) + + assert.Equal(t, uint64(5), btlCh1.GetExpiringBlock("ns1", "coll1", 3)) + assert.Equal(t, uint64(8), btlCh2.GetExpiringBlock("ns3", "coll4", 3)) + assert.Equal(t, uint64(math.MaxUint64), btlCh2.GetExpiringBlock("ns3", "coll4", math.MaxUint64-uint64(2))) + assert.Equal(t, uint64(math.MaxUint64), btlCh2.GetExpiringBlock("ns1", "coll5", math.MaxUint64-uint64(2))) +}