-
Notifications
You must be signed in to change notification settings - Fork 198
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Bug fix/sync multiple tries #1864
Changes from 4 commits
40ea2ed
43d4ef9
6d720b3
0d73b65
b26eb67
47cbc1a
bfcef6f
96c0346
d1a6c27
0ca11a3
bcd2e00
075fa3b
21eeac9
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,8 +2,11 @@ package syncer | |
|
||
import ( | ||
"context" | ||
"sync" | ||
"time" | ||
|
||
logger "github.com/ElrondNetwork/elrond-go-logger" | ||
"github.com/ElrondNetwork/elrond-go/core/check" | ||
"github.com/ElrondNetwork/elrond-go/data" | ||
"github.com/ElrondNetwork/elrond-go/data/state" | ||
"github.com/ElrondNetwork/elrond-go/data/trie" | ||
|
@@ -15,14 +18,19 @@ var _ epochStart.AccountsDBSyncer = (*userAccountsSyncer)(nil) | |
|
||
var log = logger.GetOrCreate("syncer") | ||
|
||
const timeBetweenRetries = 100 * time.Millisecond | ||
|
||
type userAccountsSyncer struct { | ||
*baseAccountsSyncer | ||
throttler data.GoRoutineThrottler | ||
syncerMutex sync.Mutex | ||
} | ||
|
||
// ArgsNewUserAccountsSyncer defines the arguments needed for the new account syncer | ||
type ArgsNewUserAccountsSyncer struct { | ||
ArgsNewBaseAccountsSyncer | ||
ShardId uint32 | ||
ShardId uint32 | ||
Throttler data.GoRoutineThrottler | ||
} | ||
|
||
// NewUserAccountsSyncer creates a user account syncer | ||
|
@@ -32,6 +40,10 @@ func NewUserAccountsSyncer(args ArgsNewUserAccountsSyncer) (*userAccountsSyncer, | |
return nil, err | ||
} | ||
|
||
if check.IfNil(args.Throttler) { | ||
return nil, data.ErrNilThrottler | ||
} | ||
|
||
b := &baseAccountsSyncer{ | ||
hasher: args.Hasher, | ||
marshalizer: args.Marshalizer, | ||
|
@@ -48,6 +60,7 @@ func NewUserAccountsSyncer(args ArgsNewUserAccountsSyncer) (*userAccountsSyncer, | |
|
||
u := &userAccountsSyncer{ | ||
baseAccountsSyncer: b, | ||
throttler: args.Throttler, | ||
} | ||
|
||
return u, nil | ||
|
@@ -81,25 +94,67 @@ func (u *userAccountsSyncer) SyncAccounts(rootHash []byte) error { | |
} | ||
|
||
func (u *userAccountsSyncer) syncAccountDataTries(rootHashes [][]byte, ctx context.Context) error { | ||
var errFound error | ||
errMutex := sync.Mutex{} | ||
|
||
for _, rootHash := range rootHashes { | ||
dataTrie, err := trie.NewTrie(u.trieStorageManager, u.marshalizer, u.hasher, u.maxTrieLevelInMemory) | ||
if err != nil { | ||
return err | ||
for { | ||
if u.throttler.CanProcess() { | ||
break | ||
} | ||
|
||
select { | ||
case <-time.After(timeBetweenRetries): | ||
continue | ||
case <-ctx.Done(): | ||
return data.ErrTimeIsOut | ||
} | ||
} | ||
|
||
u.dataTries[string(rootHash)] = dataTrie | ||
trieSyncer, err := trie.NewTrieSyncer(u.requestHandler, u.cacher, dataTrie, u.shardId, factory.AccountTrieNodesTopic) | ||
if err != nil { | ||
return err | ||
go func(trieRootHash []byte) { | ||
newErr := u.syncDataTrie(trieRootHash, ctx) | ||
if newErr != nil { | ||
errMutex.Lock() | ||
errFound = newErr | ||
errMutex.Unlock() | ||
} | ||
}(rootHash) | ||
|
||
errMutex.Lock() | ||
if errFound != nil { | ||
returnErr := errFound | ||
errMutex.Unlock() | ||
return returnErr | ||
} | ||
u.trieSyncers[string(rootHash)] = trieSyncer | ||
} | ||
|
||
err = trieSyncer.StartSyncing(rootHash, ctx) | ||
if err != nil { | ||
return err | ||
} | ||
return nil | ||
} | ||
|
||
func (u *userAccountsSyncer) syncDataTrie(rootHash []byte, ctx context.Context) error { | ||
u.throttler.StartProcessing() | ||
|
||
u.syncerMutex.Lock() | ||
dataTrie, err := trie.NewTrie(u.trieStorageManager, u.marshalizer, u.hasher, u.maxTrieLevelInMemory) | ||
if err != nil { | ||
return err | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. u.syncerMutex.Unlock() before return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
} | ||
|
||
u.dataTries[string(rootHash)] = dataTrie | ||
trieSyncer, err := trie.NewTrieSyncer(u.requestHandler, u.cacher, dataTrie, u.shardId, factory.AccountTrieNodesTopic) | ||
if err != nil { | ||
return err | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. u.syncerMutex.Unlock() before return There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
} | ||
u.trieSyncers[string(rootHash)] = trieSyncer | ||
u.syncerMutex.Unlock() | ||
|
||
err = trieSyncer.StartSyncing(rootHash, ctx) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
u.throttler.EndProcessing() | ||
|
||
return nil | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -18,6 +18,9 @@ var _ epochStart.RequestHandler = (*resolverRequestHandler)(nil) | |
|
||
var log = logger.GetOrCreate("dataretriever/requesthandlers") | ||
|
||
const minHashesToRequest = 10 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please replace line 456 from addRequestedItems method with continue instead return. This will fix the situation when the call of rrh.requestedItemsHandler.Add for a key, fails for whatever reason, and because of this the all others keys would not be added in the requested items list. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
const timeToAccumulateTrieHashes = 100 * time.Millisecond | ||
|
||
type resolverRequestHandler struct { | ||
epoch uint32 | ||
shardID uint32 | ||
|
@@ -28,6 +31,10 @@ type resolverRequestHandler struct { | |
sweepTime time.Time | ||
requestInterval time.Duration | ||
mutSweepTime sync.Mutex | ||
|
||
trieHashAccumulator [][]byte | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. trieHashesAcumulator ? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done |
||
lastTrieRequestTime time.Time | ||
mutexTrieHashes sync.Mutex | ||
} | ||
|
||
// NewResolverRequestHandler creates a requestHandler interface implementation with request functions | ||
|
@@ -64,6 +71,7 @@ func NewResolverRequestHandler( | |
maxTxsToRequest: maxTxsToRequest, | ||
whiteList: whiteList, | ||
requestInterval: requestInterval, | ||
trieHashAccumulator: make([][]byte, 0), | ||
} | ||
|
||
rrh.sweepTime = time.Now() | ||
|
@@ -346,10 +354,22 @@ func (rrh *resolverRequestHandler) RequestTrieNodes(destShardID uint32, hashes [ | |
if len(unrequestedHashes) == 0 { | ||
return | ||
} | ||
|
||
rrh.mutexTrieHashes.Lock() | ||
defer rrh.mutexTrieHashes.Unlock() | ||
|
||
rrh.trieHashAccumulator = append(rrh.trieHashAccumulator, unrequestedHashes...) | ||
elapsedTime := time.Since(rrh.lastTrieRequestTime) | ||
if len(rrh.trieHashAccumulator) < minHashesToRequest && elapsedTime < timeToAccumulateTrieHashes { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if the last bulk of trieHashes is smaller than 10? Let say 8. This will make the method to return in this point. It would be called again for the same 8 hashes after a while?
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think you should either call: rrh.addRequestedItems(rrh.trieHashAccumulator) before return or better rrh.trieHashAccumulator = rrh.trieHashAccumulator[:0] and add them again in the next call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are also other exit points below so I think you should put this line: rrh.trieHashAccumulator = rrh.trieHashAccumulator[:0], in a defer method above and remove it from line 400 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. the request trie hashes method is called in a continuous way at every second. Thus the accumulated hashes will be surely requested. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Then you need only to manage the duplicate hashes added in rrh.trieHashAccumulator after each call There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done with MAP. |
||
return | ||
} | ||
|
||
rrh.lastTrieRequestTime = time.Now() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Move this to line 391 where you are sure that the rrh.requestHashesWithDataSplit(rrh.trieHashAccumulator, trieResolver) would be executed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I would make requestHashesWithDataSplit to return error at least if the SplitDataInChunks call fails. And set the rrh.lastTrieRequestTime = time.Now() only if the request has been done with success. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. done. |
||
|
||
log.Debug("requesting trie nodes from network", | ||
"topic", topic, | ||
"shard", destShardID, | ||
"num nodes", len(unrequestedHashes), | ||
"num nodes", len(rrh.trieHashAccumulator), | ||
"firstHash", unrequestedHashes[0], | ||
) | ||
|
||
|
@@ -369,15 +389,15 @@ func (rrh *resolverRequestHandler) RequestTrieNodes(destShardID uint32, hashes [ | |
return | ||
} | ||
|
||
for _, txHash := range hashes { | ||
for _, txHash := range rrh.trieHashAccumulator { | ||
log.Trace("requestByHashes", "hash", txHash) | ||
} | ||
|
||
rrh.whiteList.Add(unrequestedHashes) | ||
|
||
go rrh.requestHashesWithDataSplit(unrequestedHashes, trieResolver) | ||
rrh.whiteList.Add(rrh.trieHashAccumulator) | ||
rrh.requestHashesWithDataSplit(rrh.trieHashAccumulator, trieResolver) | ||
rrh.addRequestedItems(rrh.trieHashAccumulator) | ||
|
||
rrh.addRequestedItems(unrequestedHashes) | ||
rrh.trieHashAccumulator = rrh.trieHashAccumulator[:0] | ||
} | ||
|
||
// RequestMetaHeaderByNonce method asks for meta header from the connected peers by nonce | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Missing errMutex.Unlock() after line 128. I suggest to replace the code between lines 123-128 with:
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done