-
Notifications
You must be signed in to change notification settings - Fork 3
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
feat: new BlockWriter implementation for block-as-file #355
base: main
Are you sure you want to change the base?
feat: new BlockWriter implementation for block-as-file #355
Conversation
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
…l remain Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
1e81bdb
to
2d82213
Compare
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
Intermediate thoughts at 9fa5c10:
|
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
… clean up approach Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
Update at 5c0a707:
|
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
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.
A few areas that could be improved.
* positive | ||
*/ | ||
public static long requirePositive(final long toCheck, final String errorMessage) { | ||
if (0 >= toCheck) { |
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.
nit: 0
==>> 0L
.
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.
server/docs/configuration.md
Outdated
@@ -16,3 +16,4 @@ defaults and can be left unchanged. It is recommended to browse the properties b | |||
| SERVICE_DELAY_MILLIS | Service shutdown delay in milliseconds | 500 | | |||
| MEDIATOR_RING_BUFFER_SIZE | Size of the ring buffer used by the mediator (must be a power of 2) | 67108864 | | |||
| NOTIFIER_RING_BUFFER_SIZE | Size of the ring buffer used by the notifier (must be a power of 2) | 2048 | | |||
| PERSISTENCE_STORAGE_TYPE | Type of the persistence storage | BLOCK_AS_FILE | |
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.
BLOCK_AS_FILE
==> BLOCK_AS_LOCAL_FILE
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.
@NonNull final BlockNodeContext blockNodeContext, | ||
@NonNull final BlockRemover blockRemover, | ||
@NonNull final PathResolver pathResolver) { | ||
Objects.requireNonNull(blockNodeContext); |
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 can remove this line; the first line of the code will throw if this is null.
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.
case null -> throw new NullPointerException( | ||
"Persistence StorageType cannot be [null], cannot create an instance of BlockWriter"); |
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.
This is not good. Either the type should be guaranteed non null from config, or use Objects.requireNonNull
right before this switch.
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.
What you were looking at is outdated, it was removed before your review.
static BlockReader<Block> providesBlockReader(PersistenceStorageConfig config) { | ||
return BlockAsDirReaderBuilder.newBuilder(config).build(); | ||
static BlockReader<Block> providesBlockReader(@NonNull final PersistenceStorageConfig config) { | ||
final StorageType persistenceType = Objects.requireNonNull(config).type(); |
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.
Objects.requireNonNull
is unnecessary if the call would throw NPE anyway, and the native throw will usually produce better information.
final StorageType persistenceType = Objects.requireNonNull(config).type(); | |
final StorageType persistenceType = config.type(); |
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.
} catch (final Exception e) { | ||
// todo handle properly | ||
throw new RuntimeException(e); | ||
} |
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.
Unless you have a very good reason, do not catch Exception
, ever (a vast array of bugs in real systems come from this seemingly innocuous block).
Instead, handle any specific exceptions you can, declare any checked exceptions necessary, and let callers handle things from there.
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.
The try-catch here would probably be greatly reworked or removed from here. This was done just to help develop the core functionality.
throw new RuntimeException(e); | ||
} | ||
curentBlock = null; | ||
return Optional.of(blockToWrite.items()); |
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 do we return an Optional
if we never return an empty value?
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 true, at this point, we do not really need to, the place where I call this method requires the Optional
wrapping since I return it immediately and the API returns Optional
, but yes, the wrapping could be done by the caller of this method, rather than proactively by the method.
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.
* @param blockPathResolver valid, {@code non-null} instance of {@link BlockPathResolver} | ||
* @return a new instance of {@link BlockAsFileWriterBuilder} | ||
*/ | ||
public static BlockAsFileWriterBuilder newBuilder( |
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.
Builder constructors should not, in general, take parameters. The whole point of a "builder" is to start empty and set each value as needed (chained by returning the builder from each set method) before a build
produces the result value.
What you've written here is an oddly structured factory, rather than a builder.
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 agree about the builders, in fact, I prefer to implement Joshua Bloch's builder where we have Builder
class that is internal to the class we want to build, since we can access directly the private filed of the internal builder from the target class and pass the builder itself as a constructor parameter.
I also agree that the builder should start "empty" and we set each value as needed.
I do not agree however that the builder constructor or static method that gets us the builder instance should have no arguments. There are some things that are mandatory for the given instance that will be constructed. Without forcing the caller to supply them, it is very error prone. The optional stuff should be settable later.
In our case it really looks like an odd factory, in fact I was thinking if we need the builders at all, we could just have static of()
or from()
or similar method directly inside the target class and omit the builders. The only place where we currently have an optional value is the folderPermissions
which I will remove the possibility to be set externally, they shall remain an internal property of the class. All other builders are in the same fashion.
There are two views here in my opinion.
- We simplify and remove the builders as they are not needed at all at this point, no need to support them.
- We keep the builders as they are with the thinking that if in the future will appear optional dependencies they will be introduced within the builder as setters and our refactoring will be minimal.
UNRELATED SIDE NOTE: In some rare cases where we have a very complex building logic that requires some things to be set before others or when setting something then we must proceed with additional settings for what we just set, then I like to do interactive builders where I have multiple interfaces with specific setters and my builder implements all giving me the possibility to guide the caller through the possible options at any given step, returning a specific interface. (not applicable at all to us, just an interesting side note)
* @return an optional containing the block item written to storage if the block item was a | ||
* block proof signaling the end of the block, an empty optional otherwise. | ||
* @throws IOException when failing to write the block item to storage. | ||
*/ | ||
Optional<V> write(@NonNull final V blockItem) throws IOException; | ||
Optional<V> write(@NonNull final V toWrite) throws IOException; |
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.
nit: toWrite
feels a bit short. itemToWrite
reads better.
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 necessary an item, sometimes it could be a Block
(not present today) or as it is today List<BlockItem>
which is plural and still does not match the semantics. I rely on the parameter's type to supplement the semantics for what we are writing, so whatever the type will be, it will always be followed by toWrite
.
|
||
#Persistence Storage Config | ||
#persistence.storage.rootPath= | ||
#persistence.storage.type=BLOCK_AS_DIR |
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.
Remember to include newlines at EOF.
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.
Hmm should have been done automatically by my IDE, Ill take look, thanks for noticing!
On a side note, is it not possible to ensure this with spotless? Would be good if we can do that.
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.
@jsync-swirlds thanks for the review, I have missed a couple of places where I could clean up additionally, however at some places it looks like you were looking at older changes, files were amended before you have made your review. I have also included #319 here and will bring additional changes to the exception handling to clean that up as well. |
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
Signed-off-by: Atanas Atanasov <a.v.atanasov98@gmail.com>
Description:
This PR aims to introduce the new
BlockAsFileWriter
with the initial goal to only be able to write blocks as file. In subsequent PRs this functionality will be improved and cleaned up. You can see #309 for more details on the full functionality that will be implemented.Related issue(s):
Fixes #281 #319
Notes for reviewer:
TBD
Checklist