Skip to content
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

Fix concurrent modification #218

Merged
merged 2 commits into from
Dec 6, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2550,94 +2550,40 @@ protected LockState lock(Node node, Config config) throws OnlyofficeEditorExcept
}
}

Config.Editor.User user = config.getEditorConfig().getUser();
LockState lock;
int attempts = 0;
try {
do {
attempts++;
if (node.isLocked()) {
// need wait for unlock
if(LOG.isDebugEnabled()) {
LOG.debug("Node (id={},path={}) is already locked. (userId={})",
node.getUUID(), node.getPath(), config.getEditorConfig().getUser().getId());
}
String lockToken;
try {
lockToken = LockUtil.getLockToken(node);
if(LOG.isDebugEnabled()) {
LOG.debug("Node (id={},path={}) is locked with token={}. (userId={})",
node.getUUID(), node.getPath(),lockToken,config.getEditorConfig().getUser().getId());
}
} catch (Exception e) {
if (RepositoryException.class.isAssignableFrom(e.getClass())) {
throw RepositoryException.class.cast(e);
} else {
logError(config.getEditorConfig().getUser().getId(),
node.getPath(),
node.getUUID(),
config.getDocument().getKey(),
"Error reading document lock");
throw new OnlyofficeEditorException("Error reading document lock", e);
}
}

if (node.getLock().getLockOwner().equals(user.getId()) && lockToken != null) {
if(LOG.isDebugEnabled()) {
LOG.debug("Node (id={},path={}) is locked by currentUser : lockOwner={}, lockToken={}. (userId={})",
node.getUUID(), node.getPath(), node.getLock().getLockOwner(), lockToken, config.getEditorConfig().getUser().getId());
}
// already this user lock
node.getSession().addLockToken(lockToken);
lock = new LockState(lockToken);
if(LOG.isDebugEnabled()) {
LOG.debug("New lock token ({}) added to node (id={},path={}). (userId={})",
lockToken,
node.getUUID(),
node.getPath(),
config.getEditorConfig().getUser().getId());
}
} else {
// need wait for unlock
if(LOG.isDebugEnabled()) {
LOG.debug("Wait {} ms before retrying to take lock on node (id={},path={}). (userId={})",
LOCK_WAIT_TIMEOUT,
node.getUUID(),
node.getPath(),
config.getEditorConfig().getUser().getId());
}
Thread.sleep(LOCK_WAIT_TIMEOUT);
lock = null;
LOG.debug("Wait {} ms before retrying to take lock on node (id={},path={}). (userId={})",
LOCK_WAIT_TIMEOUT,
node.getUUID(),
node.getPath(),
config.getEditorConfig().getUser().getId());
}
Thread.sleep(LOCK_WAIT_TIMEOUT);
lock = null;
} else {
if(LOG.isDebugEnabled()) {
LOG.debug("Node (id={},path={}) is not locked, take the lock. (userId={})",
node.getUUID(), node.getPath(), config.getEditorConfig().getUser().getId());
}
Lock jcrLock = node.lock(true, false);
if(LOG.isDebugEnabled()) {
LOG.debug("Node (id={},path={}) is now locked. (userId={})",
node.getUUID(), node.getPath(), config.getEditorConfig().getUser().getId());
}
// keep lock token for other sessions of same user
try {
LockUtil.keepLock(jcrLock, user.getId(), jcrLock.getLockToken());
if(LOG.isDebugEnabled()) {
LOG.debug("Node (id={},path={}) is now locked and accept other lock for user. (userId={})",
if (LOG.isDebugEnabled()) {
LOG.debug("Node (id={},path={}) is not locked, take the lock. (userId={})",
node.getUUID(), node.getPath(), config.getEditorConfig().getUser().getId());
}
} catch (Exception e) {
if (RepositoryException.class.isAssignableFrom(e.getClass())) {
throw RepositoryException.class.cast(e);
} else {
logError(config.getEditorConfig().getUser().getId(),
node.getPath(),
node.getUUID(),
config.getDocument().getKey(),
"Error saving document lock");
throw new OnlyofficeEditorException("Error saving document lock", e);
Lock jcrLock = node.lock(true, false);
if (LOG.isDebugEnabled()) {
LOG.debug("Node (id={},path={}) is now locked. (userId={})",
node.getUUID(), node.getPath(), config.getEditorConfig().getUser().getId());
}
lock = new LockState(jcrLock);
} catch (Exception e) {
LOG.warn("Unable to get the lock on node (id={},path={}). Probably because on concurrent access. (userId={})",
node.getUUID(), node.getPath(), config.getEditorConfig().getUser().getId(), e);
lock = null;

}
lock = new LockState(jcrLock);
}
} while (lock == null && attempts <= LOCK_WAIT_ATTEMTS);
} catch (InterruptedException e) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,8 @@ public Map<String,Config> getConfigsByKey(String key) {
List<EditorConfigEntity> entities = editorConfigDAO.getConfigByKey(key);
return entities.stream()
.collect(Collectors.toMap(EditorConfigEntity::getEditorUserUserid,
this::buildFromEntity));
this::buildFromEntity,
(key1, key2) -> key1));
}

@Override
Expand All @@ -36,7 +37,9 @@ public Map<String,Config> getConfigsByDocId(String docId) {
List<EditorConfigEntity> entities = editorConfigDAO.getConfigByDocId(docId);
return entities.stream()
.collect(Collectors.toConcurrentMap(EditorConfigEntity::getEditorUserUserid,
this::buildFromEntity)); }
this::buildFromEntity,
(key1, key2) -> key1));
}



Expand Down