-
Notifications
You must be signed in to change notification settings - Fork 38
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
Introduce Peapod #2462
Introduce Peapod #2462
Conversation
959689e
to
a7318e7
Compare
Codecov Report
@@ Coverage Diff @@
## master #2462 +/- ##
==========================================
+ Coverage 29.30% 29.65% +0.35%
==========================================
Files 399 401 +2
Lines 30347 30620 +273
==========================================
+ Hits 8892 9081 +189
- Misses 20719 20773 +54
- Partials 736 766 +30
... and 1 file with indirect coverage changes 📣 We’re building smart automated test selection to slash your CI/CD build times. Learn more |
err := x.bolt.View(func(tx *bbolt.Tx) error { | ||
bktRoot := tx.Bucket(rootBucket) | ||
if bktRoot == nil { | ||
return fmt.Errorf("%w: missing root bucket", apistatus.ErrObjectNotFound) |
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.
We usually use fmt.Errorf("some text: %w", err)
pattern. In this function exists two different patterns for errors, with %w
in the end and in the beginning.
Is it an exceptional situation to change this format here?
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.
usually reason goes after colon, and here missing root bucket
is a particular reason of object not found
(there may be other reasons). Here we could just return apistatus.ErrObjectNotFound
, but additional context is good.
u may encounter similar cases in the code base
func (x *Peapod) flushLoop() { | ||
defer close(x.chFlushDone) | ||
|
||
ticker := time.NewTicker(10 * time.Millisecond) |
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.
Do we plan to adjust the value from the external config? I think even no, this is a magic const
here, it would be better to put it in the const
section above
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.
right now it doesn't make sense to expose this interval as config because we don't have strict model of how it changes the performance (i reached the current value experimentally). Having dedicated const is not bad but it'll be used in single place, i don't mind
29f76c4
to
6c50e19
Compare
added all ops and made
|
@@ -0,0 +1,70 @@ | |||
package peapod |
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.
why the files are named read
and write
? usually we use put
and get
like the methods are
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.
united methods using similar code in a separate source file, imo this is easier to maintain then per-method files. U think?
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.
as always, i am for unification, so i would like it to be the same for every common.Storage
implementation
talking about naming: not that critical but i still think that method per file is preferable. files' number is not that big but more details are always welcome (once again, it there are not a lot of details, num of methods not gonna exceed 20, i think)
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.
then i'll need to add more files to place shared reusable methods like batch
into and we'll come to file:func 1:1, i'd prefer to group related code in single source file, but don't mind to split (more minor changes taking time)
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.
Files should group some sets of code logically, one file per function doesn't help much, you get too many files quickly and then duplicate imports in all of them, don't remember which of them has some constant defined, switch between them in editor. Likely this is not the biggest problem we have.
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.
then lets leave introduced file structure as it is (it's shorter and unites similar code at least), we'll always be able to change things later in off season (i know we dont have one 😺). This wasnt a proposal "lets do like this everywhere from now", just new independent autonomous package
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.
one file per function doesn't help much
i wasn't talking about func per file. i was more about a single approach: we had 7 "storage for object data" packages that did Put
in a file named put.go
and now we are going to have a single pkg that does Put
in a file named write.go
. also, i am ok with both approaches but we have a little number of "API" (not so many operations with an object can be done) calls and are not going to "get too many files quickly"
c0ea07b
to
115c649
Compare
115c649
to
518a1ad
Compare
return apistatus.ErrObjectNotFound | ||
} | ||
|
||
data = slice.Copy(val) |
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.
i have already asked somewhere but did not get the answer: why do we keep importing that non-neo-go util from neo-go
?
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.
Maybe because it's so nice and solves the problem?
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.
in next go upgrades we'll use bytes.Clone
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.
Maybe because it's so nice and solves the problem?
Sure it does, but I am so excited about why do we need to import it in this repo and why everybody is OK with it. Extremely strange to me: simple util that can be done by everyone and it should take < 1m but we are keeping importing it. It does not relate neo-go
absolutely.
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.
so iiuc u suggest either duplicate this in neofs-node
or write 2 lines in-place or ..?
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.
@carpawell so you don't mind using this feature?
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.
it is not a problem for me, i just do not get it. it won't stop me from pressing "Approve"
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.
it won't stop me from pressing "Approve"
i mean when bytes.Clone
(or even slices.Clone
) will become available with newer Go version - u'll be still against using those utilities?
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.
u'll be still against using those utilities?
nono, of course, no. "i need neo-go
to copy bytes" sounds strange to me and that's it. using std for that purpose is just as natural as possible (when it is released)
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.
It's not that you need neo-go
, it's that you already have it. Introducing it as a dependency just for this function would be inappropriate, but we're already dependent on it for different reasons, so reusing some functions is just a natural thing to do. And yes, it'll all be changed with newer Go.
ad22084
to
d9b45a5
Compare
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.
Conflicts.
0438519
to
4060955
Compare
ec75f9d
to
7d09562
Compare
1ac5ee0
to
f4e2512
Compare
Currently, storage node saves relatively small NeoFS objects in Blobovnicza tree component: group of BoltDB wrappers managed as a tree. This component has pretty complex data structure, code implementation and dubious performance results. Peapod is a new storage component introduced to replace Blobovnicza one as more simple and effective. It also bases on single BoltDB instance, but organizes batch writes in a specific way. In future, Peapod is going to be used as a storage of small objects by the BlobStor. Refs nspcc-dev#2453. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
0b9556a
to
9bba966
Compare
Add `cmd/blobovnicza-to-peapod` application which accepts YAML configuration file of the storage node and, for each configured shard, overtakes data from Blobovnicza tree to Peapod created in the parent directory. The tool is going to be used for phased and safe rejection of the Blobovnicza trees and the transition to Peapods. Refs nspcc-dev#2453. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Error wrapping is normal, so we should always be ready to it. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
Support `peapod` sub-storage type in BlobStor configuration. Refs nspcc-dev#2453. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
There may be a need to tune time interval b/w batch writes to disk in Peapod component. Add storage node's config with `flush_interval` key of type duration defaulting to 10ms. Signed-off-by: Leonard Lyubich <leonard@morphbits.io>
9bba966
to
b01baf6
Compare
Unbreak peapods: 2023/09/13 18:50:36 open shard S4wpuCnzpWW7SbwhER3U1v: could not open *blobstor.BlobStor: open substorage peapod: open BoltDB instance: open /storage/peapod0.db: is a directory Call `stat()` gently instead walking up. FS mount point has to exist there in any event and we should have some access to it. The real problem is that #2462 (introducing Peapod) was correct on its own. And #2495 (introducing capacity) was also correct on its own. But they don't work together. Refs 7c54307. Refs c060b16. util.MkdirAllX will be removed from code in most of the cases. Signed-off-by: Roman Khimov <roman@nspcc.ru>
Unbreak peapods: 2023/09/13 18:50:36 open shard S4wpuCnzpWW7SbwhER3U1v: could not open *blobstor.BlobStor: open substorage peapod: open BoltDB instance: open /storage/peapod0.db: is a directory Call `stat()` gently instead walking up. FS mount point has to exist there in any event and we should have some access to it. The real problem is that #2462 (introducing Peapod) was correct on its own. And #2495 (introducing capacity) was also correct on its own. But they don't work together. Refs 7c54307. Refs c060b16. util.MkdirAllX will be removed from code in most of the cases. Signed-off-by: Roman Khimov <roman@nspcc.ru>
Unbreak peapods: 2023/09/13 18:50:36 open shard S4wpuCnzpWW7SbwhER3U1v: could not open *blobstor.BlobStor: open substorage peapod: open BoltDB instance: open /storage/peapod0.db: is a directory Call `stat()` gently instead walking up. FS mount point has to exist there in any event and we should have some access to it. The real problem is that #2462 (introducing Peapod) was correct on its own. And #2495 (introducing capacity) was also correct on its own. But they don't work together. Refs 7c54307. Refs c060b16. util.MkdirAllX will be removed from code in most of the cases. Signed-off-by: Roman Khimov <roman@nspcc.ru>
P.S.: we haven't finally decided name yet, but currently
peapod
wins #2453 (comment)TODO:
Delete
Exists
Iterate
i didn't precisely try to optimize introduced implementation cuz tested against existing alternatives only. Current benchmark results against single BoltDB with
Update
andBatch
methods: