-
Notifications
You must be signed in to change notification settings - Fork 304
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
HPCC-31181 Avoid wsStore unnecessary write locks #18256
HPCC-31181 Avoid wsStore unnecessary write locks #18256
Conversation
https://track.hpccsystems.com/browse/HPCC-31181 |
@jakesmith how impactful do you think this change is? and do you see any value in doing something similar in the set() 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.
@rpastrana - please see comments
@@ -57,6 +59,11 @@ bool CDALIKVStore::createStore(const char * apptype, const char * storename, con | |||
if (maxvalsize != 0) | |||
apptree->setPropInt(DALI_KVSTORE_MAXVALSIZE_ATT, maxvalsize); | |||
|
|||
Owned<IRemoteConnection> conn = querySDS().connect(DALI_KVSTORE_PATH, myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT_KVSTORE); |
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 think this introduces a potential problem (via a race condition).
Multiple clients could reach this point, having all performed the read lock at line 28, and found the 'Store' not to exist. Then all perform this write lock (in sequence), and all perform the addPropTree, resulting in multiple ambiguous copies of the same named store.
The code will need to recheck after the write (exclusive) lock is established I think.
Also, it would be better to keep the existing connection (not release it), and use changeMode to switch from RTM_LOCK_READ to RTM_LOCK_WRITE, e.g.:
initially establish the read lock, check for the store's existence, then do a:
conn->changeMode(RTM_LOCK_WRITE);
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.
@rpastrana - please see comments.
@@ -57,6 +58,15 @@ bool CDALIKVStore::createStore(const char * apptype, const char * storename, con | |||
if (maxvalsize != 0) | |||
apptree->setPropInt(DALI_KVSTORE_MAXVALSIZE_ATT, maxvalsize); | |||
|
|||
conn->changeMode(RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT_KVSTORE); |
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 realized there's a potential problem with this approach.
If 1 client is at this point, then this changeMode will succeed, however if >1 client is here, then they all hold a read lock, and no client will be able to obtain an [exclusive] write lock because others will still have read locks.
The implementation will need to relinquish the read lock before attempting to get the exclusive lock, e.g.:
// clear read lock 1st, then establish a write lock and recheck
conn.clear();
conn.setown(querySDS().connect(DALI_KVSTORE_PATH, myProcessSession(), RTM_LOCK_WRITE, SDS_LOCK_TIMEOUT_KVSTORE));
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.
minor: I'd probably perform this rechecking before the 'apptree' creation code, i.e. immediately after line 39.
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.
@rpastrana - looks good. Some trivial comments, but mergeable as is.
LOG(MCuserInfo,"DALI Keystore createStore(): '%s' entry already exists", storename); | ||
return false; | ||
Owned<IPropertyTree> root = conn->getRoot(); | ||
if (root->hasProp(xpath.str())) |
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.
trivial/no need to change: linking root isn't necessary, i.e. condition could be:
if (conn->queryRoot()->hasProp(xpath))
LOG(MCuserInfo,"DALI Keystore createStore(): '%s' entry already exists", storename); | ||
return false; | ||
} | ||
|
||
root->addPropTree("Store", LINK(apptree)); |
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.
trivial/no need to change: trivially more efficient to do apptree.getClear() here.
{ | ||
LOG(MCuserInfo,"DALI Keystore createStore(): '%s' entry already exists", storename); | ||
return false; | ||
} |
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'd still probably move this to immediately after the write lock has established, i.e. before creating 'apptree' which will not be needed if this check establishes it's already there.
@rpastrana please squash (and address jake's final comments if you want) |
- Delays createStore write request and avoids if store pre-exists Signed-off-by: Rodrigo Pastrana <[email protected]>
ba70136
to
4ebbb38
Compare
made code block shift suggested by Jake and squashed. |
@rpastrana please can you add some detail to the jira about the potential impact (how likely, how often it would occur) |
Jira updated with requested information. If this information impacts your decision to merge, I suggest it becomes an explicit requirement for all jiras/pull requests. For my curiosity, what decision is influenced by the info requested? |
Thanks for the extra information. So a comment saying something like "99% of the time the store entry already exists, so avoid the write lock in this common case" is all I would be looking for. |
Type of change:
Checklist:
Smoketest:
Testing: