Skip to content

Commit 9226bbb

Browse files
committed
Cherry-pick IOTEX-192 Removing PutIfNotExists API db
1 parent 57ade5e commit 9226bbb

File tree

8 files changed

+67
-161
lines changed

8 files changed

+67
-161
lines changed

blockchain/blockchain.go

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import (
1313
"sync"
1414
"sync/atomic"
1515

16+
"github.com/boltdb/bolt"
1617
"github.com/facebookgo/clock"
1718
"github.com/pkg/errors"
1819

@@ -943,6 +944,16 @@ func (bc *blockchain) validateBlock(blk *Block, containCoinbase bool) error {
943944

944945
// commitBlock commits a block to the chain
945946
func (bc *blockchain) commitBlock(blk *Block) error {
947+
// Check if it is already exists, and return earlier
948+
blkHash, err := bc.dao.getBlockHash(blk.Height())
949+
if blkHash != hash.ZeroHash32B {
950+
logger.Debug().Uint64("height", blk.Height()).Msg("Block already exists")
951+
return nil
952+
}
953+
// If it's a ready db io error, return earlier with the error
954+
if errors.Cause(err) != db.ErrNotExist && errors.Cause(err) != bolt.ErrBucketNotFound {
955+
return err
956+
}
946957
// write block into DB
947958
if err := bc.dao.putBlock(blk); err != nil {
948959
return err

blockchain/blockchain_test.go

Lines changed: 4 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -378,12 +378,11 @@ func TestLoadBlockchainfromDB(t *testing.T) {
378378
require.NotNil(err)
379379
fmt.Printf("Cannot validate block %d: %v\n", blk.Height(), err)
380380

381-
// cannot add existing block again
381+
// add existing block again will have no effect
382382
blk, err = bc.GetBlockByHeight(3)
383383
require.NotNil(blk)
384384
require.Nil(err)
385-
err = bc.(*blockchain).commitBlock(blk)
386-
require.NotNil(err)
385+
require.NoError(bc.(*blockchain).commitBlock(blk))
387386
fmt.Printf("Cannot add block 3 again: %v\n", err)
388387

389388
// check all Tx from block 4
@@ -584,12 +583,11 @@ func TestLoadBlockchainfromDBWithoutExplorer(t *testing.T) {
584583
err = bc.ValidateBlock(blk, true)
585584
require.NotNil(err)
586585
fmt.Printf("Cannot validate block %d: %v\n", blk.Height(), err)
587-
// cannot add existing block again
586+
// add existing block again will have no effect
588587
blk, err = bc.GetBlockByHeight(3)
589588
require.NotNil(blk)
590589
require.Nil(err)
591-
err = bc.(*blockchain).commitBlock(blk)
592-
require.NotNil(err)
590+
require.NoError(bc.(*blockchain).commitBlock(blk))
593591
fmt.Printf("Cannot add block 3 again: %v\n", err)
594592
// check all Tx from block 4
595593
blk, err = bc.GetBlockByHeight(4)

blockchain/blockdao.go

Lines changed: 35 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ package blockchain
99
import (
1010
"context"
1111

12+
"github.com/boltdb/bolt"
1213
"github.com/pkg/errors"
1314

1415
"github.com/iotexproject/iotex-core/action"
@@ -86,33 +87,44 @@ func (dao *blockDAO) Start(ctx context.Context) error {
8687
}
8788

8889
// set init height value
89-
if err := dao.kvstore.PutIfNotExists(blockNS, topHeightKey, make([]byte, 8)); err != nil {
90-
// ok on none-fresh db
91-
if err == db.ErrAlreadyExist {
92-
return nil
90+
// TODO: not working with badger, we shouldn't expose detailed db error (e.g., bolt.ErrBucketExists) to application
91+
if _, err = dao.kvstore.Get(blockNS, topHeightKey); err != nil &&
92+
(errors.Cause(err) == db.ErrNotExist || errors.Cause(err) == bolt.ErrBucketNotFound) {
93+
if err := dao.kvstore.Put(blockNS, topHeightKey, make([]byte, 8)); err != nil {
94+
return errors.Wrap(err, "failed to write initial value for top height")
9395
}
94-
95-
return errors.Wrap(err, "failed to write initial value for top height")
9696
}
9797

9898
// set init total transfer to be 0
99-
if err = dao.kvstore.PutIfNotExists(blockNS, totalTransfersKey, make([]byte, 8)); err != nil {
100-
return errors.Wrap(err, "failed to write initial value for total transfers")
99+
if _, err := dao.kvstore.Get(blockNS, totalTransfersKey); err != nil &&
100+
(errors.Cause(err) == db.ErrNotExist || errors.Cause(err) == bolt.ErrBucketNotFound) {
101+
if err = dao.kvstore.Put(blockNS, totalTransfersKey, make([]byte, 8)); err != nil {
102+
return errors.Wrap(err, "failed to write initial value for total transfers")
103+
}
101104
}
102105

103106
// set init total vote to be 0
104-
if err = dao.kvstore.PutIfNotExists(blockNS, totalVotesKey, make([]byte, 8)); err != nil {
105-
return errors.Wrap(err, "failed to write initial value for total votes")
107+
if _, err := dao.kvstore.Get(blockNS, totalVotesKey); err != nil &&
108+
(errors.Cause(err) == db.ErrNotExist || errors.Cause(err) == bolt.ErrBucketNotFound) {
109+
if err = dao.kvstore.Put(blockNS, totalVotesKey, make([]byte, 8)); err != nil {
110+
return errors.Wrap(err, "failed to write initial value for total votes")
111+
}
106112
}
107113

108114
// set init total executions to be 0
109-
if err = dao.kvstore.PutIfNotExists(blockNS, totalExecutionsKey, make([]byte, 8)); err != nil {
110-
return errors.Wrap(err, "failed to write initial value for total executions")
115+
if _, err := dao.kvstore.Get(blockNS, totalExecutionsKey); err != nil &&
116+
(errors.Cause(err) == db.ErrNotExist || errors.Cause(err) == bolt.ErrBucketNotFound) {
117+
if err = dao.kvstore.Put(blockNS, totalExecutionsKey, make([]byte, 8)); err != nil {
118+
return errors.Wrap(err, "failed to write initial value for total executions")
119+
}
111120
}
112121

113122
// set init total actions to be 0
114-
if err = dao.kvstore.PutIfNotExists(blockNS, totalActionsKey, make([]byte, 8)); err != nil {
115-
return errors.Wrap(err, "failed to write initial value for total actions")
123+
if _, err := dao.kvstore.Get(blockNS, totalActionsKey); err != nil &&
124+
(errors.Cause(err) == db.ErrNotExist || errors.Cause(err) == bolt.ErrBucketNotFound) {
125+
if err = dao.kvstore.Put(blockNS, totalActionsKey, make([]byte, 8)); err != nil {
126+
return errors.Wrap(err, "failed to write initial value for total actions")
127+
}
116128
}
117129

118130
return nil
@@ -633,7 +645,7 @@ func (dao *blockDAO) putBlock(blk *Block) error {
633645
return errors.Wrap(err, "failed to serialize block")
634646
}
635647
hash := blk.HashBlock()
636-
batch.PutIfNotExists(blockNS, hash[:], serialized, "failed to put block")
648+
batch.Put(blockNS, hash[:], serialized, "failed to put block")
637649

638650
hashKey := append(hashPrefix, hash[:]...)
639651
batch.Put(blockHashHeightMappingNS, hashKey, height, "failed to put hash -> height mapping")
@@ -770,7 +782,7 @@ func putTransfers(dao *blockDAO, blk *Block, batch db.KVStoreBatch) error {
770782
// put new transfer to sender
771783
senderKey := append(transferFromPrefix, transfer.Sender()...)
772784
senderKey = append(senderKey, byteutil.Uint64ToBytes(senderTransferCount)...)
773-
batch.PutIfNotExists(blockAddressTransferMappingNS, senderKey, transferHash[:],
785+
batch.Put(blockAddressTransferMappingNS, senderKey, transferHash[:],
774786
"failed to put transfer hash %x for sender %x", transfer.Hash(), transfer.Sender())
775787

776788
// update sender transfers count
@@ -795,7 +807,7 @@ func putTransfers(dao *blockDAO, blk *Block, batch db.KVStoreBatch) error {
795807
recipientKey := append(transferToPrefix, transfer.Recipient()...)
796808
recipientKey = append(recipientKey, byteutil.Uint64ToBytes(recipientTransferCount)...)
797809

798-
batch.PutIfNotExists(blockAddressTransferMappingNS, recipientKey, transferHash[:],
810+
batch.Put(blockAddressTransferMappingNS, recipientKey, transferHash[:],
799811
"failed to put transfer hash %x for recipient %x", transfer.Hash(), transfer.Recipient())
800812

801813
// update recipient transfers count
@@ -834,7 +846,7 @@ func putVotes(dao *blockDAO, blk *Block, batch db.KVStoreBatch) error {
834846
// put new vote to sender
835847
senderKey := append(voteFromPrefix, Sender...)
836848
senderKey = append(senderKey, byteutil.Uint64ToBytes(senderVoteCount)...)
837-
batch.PutIfNotExists(blockAddressVoteMappingNS, senderKey, voteHash[:],
849+
batch.Put(blockAddressVoteMappingNS, senderKey, voteHash[:],
838850
"failed to put vote hash %x for sender %x", voteHash, Sender)
839851

840852
// update sender votes count
@@ -858,7 +870,7 @@ func putVotes(dao *blockDAO, blk *Block, batch db.KVStoreBatch) error {
858870
// put new vote to recipient
859871
recipientKey := append(voteToPrefix, Recipient...)
860872
recipientKey = append(recipientKey, byteutil.Uint64ToBytes(recipientVoteCount)...)
861-
batch.PutIfNotExists(blockAddressVoteMappingNS, recipientKey, voteHash[:],
873+
batch.Put(blockAddressVoteMappingNS, recipientKey, voteHash[:],
862874
"failed to put vote hash %x for recipient %x", voteHash, Recipient)
863875

864876
// update recipient votes count
@@ -895,7 +907,7 @@ func putExecutions(dao *blockDAO, blk *Block, batch db.KVStoreBatch) error {
895907
// put new execution to executor
896908
executorKey := append(executionFromPrefix, execution.Executor()...)
897909
executorKey = append(executorKey, byteutil.Uint64ToBytes(executorExecutionCount)...)
898-
batch.PutIfNotExists(blockAddressExecutionMappingNS, executorKey, executionHash[:],
910+
batch.Put(blockAddressExecutionMappingNS, executorKey, executionHash[:],
899911
"failed to put execution hash %x for executor %x", execution.Hash(), execution.Executor())
900912

901913
// update executor executions count
@@ -919,7 +931,7 @@ func putExecutions(dao *blockDAO, blk *Block, batch db.KVStoreBatch) error {
919931
// put new execution to contract
920932
contractKey := append(executionToPrefix, execution.Contract()...)
921933
contractKey = append(contractKey, byteutil.Uint64ToBytes(contractExecutionCount)...)
922-
batch.PutIfNotExists(blockAddressExecutionMappingNS, contractKey, executionHash[:],
934+
batch.Put(blockAddressExecutionMappingNS, contractKey, executionHash[:],
923935
"failed to put execution hash %x for contract %x", execution.Hash(), execution.Contract())
924936

925937
// update contract executions count
@@ -962,7 +974,7 @@ func putActions(dao *blockDAO, blk *Block, batch db.KVStoreBatch) error {
962974
// put new action to sender
963975
senderKey := append(actionFromPrefix, act.SrcAddr()...)
964976
senderKey = append(senderKey, byteutil.Uint64ToBytes(senderActionCount)...)
965-
batch.PutIfNotExists(blockAddressActionMappingNS, senderKey, actHash[:],
977+
batch.Put(blockAddressActionMappingNS, senderKey, actHash[:],
966978
"failed to put action hash %x for sender %s", actHash, act.SrcAddr())
967979

968980
// update sender action count
@@ -986,7 +998,7 @@ func putActions(dao *blockDAO, blk *Block, batch db.KVStoreBatch) error {
986998
// put new action to recipient
987999
recipientKey := append(actionToPrefix, act.DstAddr()...)
9881000
recipientKey = append(recipientKey, byteutil.Uint64ToBytes(recipientActionCount)...)
989-
batch.PutIfNotExists(blockAddressActionMappingNS, recipientKey, actHash[:],
1001+
batch.Put(blockAddressActionMappingNS, recipientKey, actHash[:],
9901002
"failed to put action hash %x for recipient %s", actHash, act.DstAddr())
9911003

9921004
// update recipient action count

blocksync/buffer.go

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -73,13 +73,8 @@ func (b *blockBuffer) Flush(blk *blockchain.Block) (bool, bCheckinResult) {
7373
}
7474
delete(b.blocks, next)
7575
if err := commitBlock(b.bc, b.ap, blk); err != nil {
76-
l.Error().Err(err).Uint64("syncHeight", next).
77-
Msg("Failed to commit the block.")
78-
// unable to commit, check reason
79-
committedBlk, err := b.bc.GetBlockByHeight(next)
80-
if err != nil || committedBlk.HashBlock() != blk.HashBlock() {
81-
break
82-
}
76+
l.Error().Err(err).Uint64("syncHeight", next).Msg("Failed to commit the block.")
77+
break
8378
}
8479
moved = true
8580
confirmedHeight = next

db/db.go

Lines changed: 0 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,6 @@ type KVStore interface {
3232

3333
// Put insert or update a record identified by (namespace, key)
3434
Put(string, []byte, []byte) error
35-
// Put puts a record only if (namespace, key) doesn't exist, otherwise return ErrAlreadyExist
36-
PutIfNotExists(string, []byte, []byte) error
3735
// Get gets a record by (namespace, key)
3836
Get(string, []byte) ([]byte, error)
3937
// Delete deletes a record by (namespace, key)
@@ -71,16 +69,6 @@ func (m *memKVStore) Put(namespace string, key, value []byte) error {
7169
return nil
7270
}
7371

74-
// PutIfNotExists inserts a <key, value> record only if it does not exist yet, otherwise return ErrAlreadyExist
75-
func (m *memKVStore) PutIfNotExists(namespace string, key, value []byte) error {
76-
m.bucket[namespace] = struct{}{}
77-
_, loaded := m.data.LoadOrStore(namespace+keyDelimiter+string(key), value)
78-
if loaded {
79-
return ErrAlreadyExist
80-
}
81-
return nil
82-
}
83-
8472
// Get retrieves a record
8573
func (m *memKVStore) Get(namespace string, key []byte) ([]byte, error) {
8674
if _, ok := m.bucket[namespace]; !ok {
@@ -121,11 +109,6 @@ func (m *memKVStore) Commit(b KVStoreBatch) (e error) {
121109
e = err
122110
break
123111
}
124-
} else if write.writeType == PutIfNotExists {
125-
if err := m.PutIfNotExists(write.namespace, write.key, write.value); err != nil {
126-
e = err
127-
break
128-
}
129112
} else if write.writeType == Delete {
130113
if err := m.Delete(write.namespace, write.key); err != nil {
131114
e = err
@@ -315,18 +298,6 @@ func (b *boltDB) Commit(batch KVStoreBatch) (err error) {
315298
if err := bucket.Put(write.key, write.value); err != nil {
316299
return errors.Wrapf(err, write.errorFormat, write.errorArgs)
317300
}
318-
} else if write.writeType == PutIfNotExists {
319-
bucket, err := tx.CreateBucketIfNotExists([]byte(write.namespace))
320-
if err != nil {
321-
return errors.Wrapf(err, write.errorFormat, write.errorArgs)
322-
}
323-
if bucket.Get(write.key) == nil {
324-
if err := bucket.Put(write.key, write.value); err != nil {
325-
return errors.Wrapf(err, write.errorFormat, write.errorArgs)
326-
}
327-
} else {
328-
return ErrAlreadyExist
329-
}
330301
} else if write.writeType == Delete {
331302
bucket := tx.Bucket([]byte(write.namespace))
332303
if bucket == nil {

db/db_batch.go

Lines changed: 0 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,6 @@ type (
2121
// b := NewBatch()
2222
// and keep batching Put/Delete operation into it
2323
// b.Put(bucket, k, v)
24-
// b.PutIfNotExists(bucket, k, v)
2524
// b.Delete(bucket, k, v)
2625
// once it's done, call KVStore interface's Commit() to persist to underlying DB
2726
// KVStore.Commit(b)
@@ -36,8 +35,6 @@ type (
3635
ClearAndUnlock()
3736
// Put insert or update a record identified by (namespace, key)
3837
Put(string, []byte, []byte, string, ...interface{})
39-
// PutIfNotExists puts a record only if (namespace, key) doesn't exist, otherwise return ErrAlreadyExist
40-
PutIfNotExists(string, []byte, []byte, string, ...interface{}) error
4138
// Delete deletes a record by (namespace, key)
4239
Delete(string, []byte, string, ...interface{})
4340
// Size returns the size of batch
@@ -85,8 +82,6 @@ const (
8582
Put int32 = iota
8683
// Delete indicate the type of write operation to be Delete
8784
Delete int32 = 1
88-
// PutIfNotExists indicate the type of write operation to be PutIfNotExists
89-
PutIfNotExists int32 = 2
9085
)
9186

9287
// NewBatch returns a batch
@@ -117,14 +112,6 @@ func (b *baseKVStoreBatch) Put(namespace string, key, value []byte, errorFormat
117112
b.batch(Put, namespace, key, value, errorFormat, errorArgs)
118113
}
119114

120-
// PutIfNotExists inserts a <key, value> record only if it does not exist yet, otherwise return ErrAlreadyExist
121-
func (b *baseKVStoreBatch) PutIfNotExists(namespace string, key, value []byte, errorFormat string, errorArgs ...interface{}) error {
122-
b.mutex.Lock()
123-
defer b.mutex.Unlock()
124-
b.batch(PutIfNotExists, namespace, key, value, errorFormat, errorArgs)
125-
return nil
126-
}
127-
128115
// Delete deletes a record
129116
func (b *baseKVStoreBatch) Delete(namespace string, key []byte, errorFormat string, errorArgs ...interface{}) {
130117
b.mutex.Lock()
@@ -202,18 +189,6 @@ func (cb *cachedBatch) Put(namespace string, key, value []byte, errorFormat stri
202189
cb.batch(Put, namespace, key, value, errorFormat, errorArgs)
203190
}
204191

205-
// PutIfNotExists inserts a <key, value> record only if it does not exist yet, otherwise return ErrAlreadyExist
206-
func (cb *cachedBatch) PutIfNotExists(namespace string, key, value []byte, errorFormat string, errorArgs ...interface{}) error {
207-
cb.lock.Lock()
208-
defer cb.lock.Unlock()
209-
if _, ok := cb.cache[cb.hash(namespace, key)]; ok {
210-
return ErrAlreadyExist
211-
}
212-
cb.cache[cb.hash(namespace, key)] = value
213-
cb.batch(PutIfNotExists, namespace, key, value, errorFormat, errorArgs)
214-
return nil
215-
}
216-
217192
// Delete deletes a record
218193
func (cb *cachedBatch) Delete(namespace string, key []byte, errorFormat string, errorArgs ...interface{}) {
219194
cb.lock.Lock()

0 commit comments

Comments
 (0)