Skip to content

Conversation

@averma21
Copy link
Member

@averma21 averma21 commented Oct 5, 2021

No description provided.

amrverma added 4 commits September 16, 2021 17:36
"if memory drop below {} GB (max {})", pool.getName(), minMemoryBytes/ONE_GB, humanReadableByteCount(maxMemory));
pool.setCollectionUsageThreshold(minMemoryBytes);
checkMemory(usage);
// todo - should we check and block in the beginning? This creates problem in case of download resume.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why does it create problems?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't see a purpose of checking the memory during the beginning. There is nothing to do in this case. The only thing we could do is not to proceed further, but such kind of check could be added even before this stage.

This one creates a problem during resume, in case memory is low due to previous run. It won't have any registered clients who still need to dump data (since previous run task objects would be unreachable) and checkMemory waits for clients to dump data. So the process blocks.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, in this case could you remove the TODO and write e.g. "We don't check memory here, as there is no good way here to free up memory in case it is low."?

.from(cd);
checkMemory(info.getUsage());
synchronized (sufficientMemory) {
if (sufficientMemory.get()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sufficientMemory is AtomicBoolean. I don't see why you would want to synchronize on it. Is the problem that you want to protect against concurrent calls on checkMemory? If yes, then checkMemory should be synchronized instead.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per the current code, we don't want to call checkMemory again, if sufficientMemory is already false, hence this approach.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm this not clear... I don't currently see an answer to the question "why you would want to synchronize on it"

File storeFile = writeToStore(storeDir, getStoreFileName());
return sortStoreFile(storeFile);
} finally {
nodeStates.close();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It sounds weird that createSortedStoreFile has a side effect of closing the nodeStates. Why?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, this looks weird since this class is not the owner of nodeStates. This has been done to prevent OOM for multi threaded download. We need to keep on closing the nodeStates as the download tasks keep on finishing. This is mainly for TraverseAndSortTask (tasks created for parallel download) but due to code flow same pattern had to be followed here.
We could improve this but some more refactoring would be needed.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see you mean that particular method - createSortedStoreFile.
I will see if we can add close method as you suggested.

memoryManager.deregisterClient(registrationID);
}
try {
nodeStates.close();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here again we close the nodeStates.... why here? What about having a separate close() method in this class?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

try (BufferedWriter writer = FlatFileStoreUtils.createWriter(newtmpfile, compressionEnabled)) {
// no concurrency issue with this traversal because addition to this list is only done in #addEntry which, for
// a given TraverseAndSortTask object will only be called from same thread
for (NodeStateHolder h : entryBatch) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ah, no, here we don't synchronize on entryBatch! That's inconsistent synchronization, and can cause big problems I think. (The way around it would be to clone entryBatch... but again, I would prefer if we don't need any synchronization).

writeToSortedFiles();
return sortStoreFile();
} finally {
nodeStates.close();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here again, closing the nodeStates as a side effect of another method... I find it weird.

amrverma added 3 commits October 20, 2021 19:05
* Using linkedlist in tasks for freeing memory early
* Dumping if data is greater than one MB
* Closing node state entry traversors using try with
* Incorporating some feedback from review comments
"if memory drop below {} GB (max {})", pool.getName(), minMemoryBytes/ONE_GB, humanReadableByteCount(maxMemory));
pool.setCollectionUsageThreshold(minMemoryBytes);
checkMemory(usage);
// todo - should we check and block in the beginning? This creates problem in case of download resume.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, in this case could you remove the TODO and write e.g. "We don't check memory here, as there is no good way here to free up memory in case it is low."?

.from(cd);
checkMemory(info.getUsage());
synchronized (sufficientMemory) {
if (sufficientMemory.get()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hm this not clear... I don't currently see an answer to the question "why you would want to synchronize on it"

try {
nodeStates.close();
} catch (IOException e) {
log.error("{} could not close NodeStateEntryTraverser", taskID);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you log the stack trace as well? Just add ", e" to the log.error call.

//Holder line consist only of json and not 'path|json'
NodeStateHolder h = new StateInBytesHolder(e.getPath(), jsonText);
entryBatch.add(h);
synchronized (this) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't understand the exact use for synchronization... which data structure needs to be protected from concurrent operations?

@thomasmueller thomasmueller self-requested a review November 30, 2021 15:16
@averma21 averma21 merged commit c04aff5 into apache:trunk Dec 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants