Skip to content

Commit

Permalink
Fix block of event bus (#8)
Browse files Browse the repository at this point in the history
This fixes a deadlock that occurs whenever a repository that
was imported from another repository with existing pushlogs
receives a post receive repository hook.

This deadlock occured,
because on the event the PushlogManager creates a semaphore
based on the id of the repository. After the pushlog has been written,
the manager tries to find and unlock this semaphore based on
the repository id stored in the pushlog. If the repository is an
imported one with a pushlog that has been created beforehand in
the original repository, this stored repository id differs from
the actual id of the current repository. Therefore the semaphore has
not been found and the lock stayed in place.

Whenever a second event has been fired for such a repository, the
manager cannot pass the semaphore, because it still is locked. This
can lead up to a complete block of the core event bus of SCM-Manager
so that no asynchronous event whatsoever can be processed any more.
This is the case, because the event bus does not call hooks of the
same type (in this case the PushlogHook) in parallel. Therefore all
further pushlog hooks will have to wait for the event that has been
blocked in the first place, which will eventually block all threads
of the event bus.

To fix this, this commit removes the redundant and error prone
repository id from the pushlog and uses the id of the repository
the event was triggered for in both places, the lock and the unlock
of the semaphore.

Because a removed fields are ignored by the xml parser loading the
pushlog enties, we do not have to adapt the data in an update step.
The repository id (and while we're at it the unused 'dataVersion', too)
simply will be omitted whenever the pushlog is changed for a repository
the next time.
  • Loading branch information
pfeuffer committed Nov 3, 2022
1 parent fbfe1c2 commit 4582103
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 106 deletions.
2 changes: 2 additions & 0 deletions gradle/changelog/event_bus_lock.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
- type: fixed
description: Block of event bus ([#8](https://github.com/scm-manager/scm-pushlog-plugin/pull/8))
92 changes: 0 additions & 92 deletions src/main/java/sonia/scm/pushlog/Pushlog.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,41 +48,8 @@
public class Pushlog implements Serializable
{

/** Field description */
private static final int DATA_VERSION = 1;

/** Field description */
private static final long serialVersionUID = 6674106880546613670L;

//~--- constructors ---------------------------------------------------------

/**
* Constructs ...
*
*/
public Pushlog() {}

/**
* Constructs ...
*
*
* @param repositoryId
*/
public Pushlog(String repositoryId)
{
this.repositoryId = repositoryId;
}

//~--- methods --------------------------------------------------------------

/**
* Method description
*
*
* @param username
*
* @return
*/
public PushlogEntry createEntry(String username)
{
PushlogEntry entry = new PushlogEntry(++lastEntryId, username);
Expand All @@ -92,16 +59,6 @@ public PushlogEntry createEntry(String username)
return entry;
}

//~--- get methods ----------------------------------------------------------

/**
* Method description
*
*
* @param id
*
* @return
*/
public String get(String id)
{
String username = null;
Expand All @@ -119,23 +76,6 @@ public String get(String id)
return username;
}

/**
* Method description
*
*
* @return
*/
public int getDataVersion()
{
return dataVersion;
}

/**
* Method description
*
*
* @return
*/
public List<PushlogEntry> getEntries()
{
if (entries == null)
Expand All @@ -146,14 +86,6 @@ public List<PushlogEntry> getEntries()
return entries;
}

/**
* Method description
*
*
* @param id
*
* @return
*/
public PushlogEntry getEntry(long id)
{
PushlogEntry entry = null;
Expand All @@ -167,36 +99,12 @@ public PushlogEntry getEntry(long id)
break;
}
}

return entry;
}

/**
* Method description
*
*
* @return
*/
public String getRepositoryId()
{
return repositoryId;
}

//~--- fields ---------------------------------------------------------------

/** Field description */
@XmlElement(name = "data-version")
private int dataVersion = DATA_VERSION;

/** Field description */
@XmlElement(name = "entry")
private List<PushlogEntry> entries;

/** Field description */
@XmlElement(name = "last-entry-id")
private long lastEntryId = 0;

/** Field description */
@XmlElement(name = "repository-id")
private String repositoryId;
}
15 changes: 7 additions & 8 deletions src/main/java/sonia/scm/pushlog/PushlogManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@
*/
package sonia.scm.pushlog;

import com.google.common.collect.Maps;
import com.google.inject.Inject;
import com.google.inject.Singleton;
import org.slf4j.Logger;
Expand All @@ -32,6 +31,7 @@
import sonia.scm.store.DataStore;
import sonia.scm.store.DataStoreFactory;

import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
Expand All @@ -49,7 +49,7 @@ public class PushlogManager {
private static final Object LOCK_STORE = new Object();
private static final Object LOCK_GET = new Object();

private final Map<String, Lock> locks = Maps.newHashMap();
private final Map<String, Lock> locks = new HashMap<>();
private final DataStoreFactory dataStoreFactory;

@Inject
Expand All @@ -61,12 +61,11 @@ public PushlogManager(DataStoreFactory dataStoreFactory) {
public void store(Pushlog pushlog, Repository repository) {
synchronized (LOCK_STORE) {
try {
logger.debug("store pushlog for repository {}",
pushlog.getRepositoryId());
logger.debug("store pushlog for repository {}", repository);
getDatastore(repository).put(NAME, pushlog);
} finally {
logger.trace("unlock repository {}", pushlog.getRepositoryId());
getLock(pushlog.getRepositoryId()).unlock();
logger.trace("unlock repository {}", repository);
getLock(repository.getId()).unlock();
}
}
}
Expand All @@ -75,7 +74,7 @@ public Pushlog get(Repository repository) {
Pushlog pushlog = getDatastore(repository).get(NAME);

if (pushlog == null) {
pushlog = new Pushlog(repository.getId());
pushlog = new Pushlog();
}

return pushlog;
Expand All @@ -90,7 +89,7 @@ public Pushlog getAndLock(Repository repository) {
synchronized (LOCK_GET) {
getLock(repository.getId()).lock();

logger.trace("lock pushlog for repository {}", repository.getId());
logger.trace("lock pushlog for repository {}", repository);

return get(repository);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -67,18 +67,18 @@ private void doUpdate(String repositoryId) {
.forRepository(repositoryId)
.build();
store.getOptional(PUSHLOG_STORE_NAME)
.ifPresent(pushlog -> optimize(store, pushlog));
.ifPresent(pushlog -> optimize(store, repositoryId, pushlog));
}

private void optimize(DataStore<Pushlog> store, Pushlog pushlog) {
if (optimize(pushlog)) {
log.info("found illegal multiple pushlog entries for repository {}; cleaning up", pushlog.getRepositoryId());
private void optimize(DataStore<Pushlog> store, String repositoryId, Pushlog pushlog) {
if (optimize(repositoryId, pushlog)) {
log.info("found illegal multiple pushlog entries for repository {}; cleaning up", repositoryId);
store.put(PUSHLOG_STORE_NAME, pushlog);
}
}

@SuppressWarnings({"java:S3011", "unchecked"}) // reflection is used only for this update step and there should be acceptable
private boolean optimize(Pushlog pushlog) {
private boolean optimize(String repositoryId, Pushlog pushlog) {
Set<String> foundChangesets = new HashSet<>();
boolean errorsFound = false;
for (Iterator<PushlogEntry> entryIterator = pushlog.getEntries().iterator(); entryIterator.hasNext(); ) {
Expand All @@ -94,7 +94,7 @@ private boolean optimize(Pushlog pushlog) {
}
}
} catch (Exception e) {
log.warn("could not clean up pushlog for repository {}", pushlog.getRepositoryId(), e);
log.warn("could not clean up pushlog for repository {}", repositoryId, e);
return false;
}
}
Expand Down

0 comments on commit 4582103

Please sign in to comment.