sn: do not treat more than a single EC part on the same node as a success#4069
sn: do not treat more than a single EC part on the same node as a success#4069carpawell wants to merge 1 commit into
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #4069 +/- ##
==========================================
+ Coverage 26.45% 26.56% +0.10%
==========================================
Files 671 671
Lines 45581 45632 +51
==========================================
+ Hits 12060 12122 +62
+ Misses 32390 32383 -7
+ Partials 1131 1127 -4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
ab98864 to
551f29e
Compare
NSPCC/git/neofs-dev-env master ✗ 1d4h ⚑ ◒
▶ neofs-cli container create -r s01.neofs.devenv:8080 --policy 'EC 3/1 CBF 1' -w wallets/wallet.json --basic-acl "public-read-write"
Enter password >
neofscontainer creation request accepted for processing (the operation may not be completed yet)
container ID: CaSmiYvN6SuQ8E7bMVzHkzLsMPEB1f9tuZYEXZNuaBFK
NSPCC/git/neofs-dev-env master ✗ 1y75d § ◒ ⍉
▶ neofs-cli object put -r s01.neofs.devenv:8080 -w wallets/wallet.json --cid CaSmiYvN6SuQ8E7bMVzHkzLsMPEB1f9tuZYEXZNuaBFK --file tmp/10Klines.txt --timeout 1m
Enter password >
100000 / 100000 [========================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================] 100.00% 0s
[tmp/10Klines.txt] Object successfully stored
OID: ExuNBE8ucepxuxHjaCPDKA3B2YMCZBwYPzST5mB9VXM7
CID: CaSmiYvN6SuQ8E7bMVzHkzLsMPEB1f9tuZYEXZNuaBFK
NSPCC/git/neofs-dev-env master ✗ 1y75d § ◒
▶ docker stop s04
s04
NSPCC/git/neofs-dev-env master ✗ 1y75d § ◒
▶ neofs-cli object put -r s01.neofs.devenv:8080 -w wallets/wallet.json --cid CaSmiYvN6SuQ8E7bMVzHkzLsMPEB1f9tuZYEXZNuaBFK --file tmp/10Klines.txt --timeout 1m
Enter password >
100000 / 100000 [=======================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================] 100.00% 40s
Error: rpc error: finish object stream: status: code = 1024 message = incomplete object PUT by placement: only 3 EC parts was put successfully for 3 data parts number, latest error: save on SN #2: could not close object stream: replicate object to remote node (key=038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35): all 038c862959e56b43e20f79187c4fe9e0bc7c8c66c1603e6cf0ec7f87ab6b08dc35 endpoints failed, first error: /dns4/s04.neofs.devenv/tcp/8080: API transport (op=/neo.fs.v2.object.ObjectService/Replicate): rpc error: code = Unavailable desc = connection error: desc = "transport: Error while dialing: dial tcp 192.168.130.74:8080: i/o timeout"
NSPCC/git/neofs-dev-env master ✗ 1y75d ⚑ ◒ ⍉
▶ docker stop s03
s03
NSPCC/git/neofs-dev-env master ✗ 1y75d ⚑ ◒
▶ neofs-cli object put -r s01.neofs.devenv:8080 -w wallets/wallet.json --cid CaSmiYvN6SuQ8E7bMVzHkzLsMPEB1f9tuZYEXZNuaBFK --file tmp/10Klines.txt --timeout 1m
Enter password >
100000 / 100000 [=======================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================] 100.00% 20s
Error: rpc error: finish object stream: status: code = 1024 message = not enought nodes for EC parts (2 parts were put) |
551f29e to
b707499
Compare
c1425f3 to
9c3418c
Compare
cc042cd to
3662963
Compare
b8bdfbe to
3662963
Compare
| err := t.applyECRule(t.sessionSigner, obj, ecRuleIdx, payloadParts, objNodeLists[ruleIdx]) | ||
| handleECRule := func(ruleIdx int, ecRuleIdx int, payloadParts [][]byte, ecRule iec.Rule) (bool, error) { | ||
| var nodes = objNodeLists[ruleIdx] | ||
| if len(nodes) < int(ecRule.DataPartNum) { |
There was a problem hiding this comment.
unrelated. And this must never happen
There was a problem hiding this comment.
not unrelated to me, this is highly used inside PR's new logic. but if it is always true (nothing is said about it in ContainerNodes interface) then ok, dropped
|
|
||
| func (t *distributedTarget) applyECRule(signer neofscrypto.Signer, obj object.Object, ruleIdx int, payloadParts [][]byte, nodeList []netmap.NodeInfo) error { | ||
| var eg errgroup.Group | ||
| var errStopECIter = errors.New("stop EC placement iteration") |
There was a problem hiding this comment.
seems redundant, it's enough returning bool from submitNodeFailure()
There was a problem hiding this comment.
err is more explicit to me that smth is wrong, ok made it bool
| } | ||
|
|
||
| func (p *ecProgress) canTryNode(n netmap.NodeInfo) bool { | ||
| if p == nil { |
There was a problem hiding this comment.
checking this by callers is more clear to me
There was a problem hiding this comment.
i read it as "no need to track progress" logic, so put it inside ecProgress. moved
| return errStopECIter | ||
| } | ||
| p.leftAvailableNodes-- | ||
| placementFailed := p.leftAvailableNodes-int(p.ecRule.DataPartNum) < 0 |
There was a problem hiding this comment.
what if there is 1 part left to save, 1 available node is left and policy is 2/1?
| var errStopECIter = errors.New("stop EC placement iteration") | ||
|
|
||
| func newECProgress(nodeList []netmap.NodeInfo, ecRule iec.Rule) *ecProgress { | ||
| nodes := make(map[string]struct{}, len(nodeList)) |
There was a problem hiding this comment.
nodeList is a set, so it's enough to deal with idxs
There was a problem hiding this comment.
Can even be a bit set. And can use atomics instead of locks then.
There was a problem hiding this comment.
not sure why you think it is critical in a routine that calculates EC objects, hashes, uses network, disks, etc, but reworked
| return fmt.Errorf("not enought nodes for EC parts (%d parts were put)", successes) | ||
| } | ||
| err.singleErr = fmt.Errorf("only %d EC parts were put successfully"+ | ||
| " for %d/%d EC rule, latest error: %w", successes, p.ecRule.DataPartNum, p.ecRule.ParityPartNum, err.singleErr) |
There was a problem hiding this comment.
| " for %d/%d EC rule, latest error: %w", successes, p.ecRule.DataPartNum, p.ecRule.ParityPartNum, err.singleErr) | |
| " for %s EC rule, latest error: %w", successes, p.ecRule, err.singleErr) |
|
|
||
| var successes = p.successPuts.Load() | ||
| if p.stop { | ||
| return fmt.Errorf("not enought nodes for EC parts (%d parts were put)", successes) |
There was a problem hiding this comment.
| return fmt.Errorf("not enought nodes for EC parts (%d parts were put)", successes) | |
| return fmt.Errorf("not enough nodes for EC parts (%d parts were put)", successes) |
| if p.stop { | ||
| return fmt.Errorf("not enought nodes for EC parts (%d parts were put)", successes) | ||
| } | ||
| err.singleErr = fmt.Errorf("only %d EC parts were put successfully"+ |
There was a problem hiding this comment.
there can be several rules with same X/Y parameters. Worth adding rule number
| var errStopECIter = errors.New("stop EC placement iteration") | ||
|
|
||
| func newECProgress(nodeList []netmap.NodeInfo, ecRule iec.Rule) *ecProgress { | ||
| nodes := make(map[string]struct{}, len(nodeList)) |
There was a problem hiding this comment.
Can even be a bit set. And can use atomics instead of locks then.
Closes #3994. Signed-off-by: Pavel Karpy <carpawell@nspcc.io>
3662963 to
d1a104e
Compare
| return false | ||
| } | ||
| p.failedPuts++ | ||
| placementFailed := len(p.nodes)-p.failedPuts < int(p.ecRule.DataPartNum) |
There was a problem hiding this comment.
EC 1/1 CBF 1, i.e. 2 nodes- 1st node fails, 1 node is left
we cannot put 2 parts, so it's a complete fail. But condition will be false
No description provided.