GH-1146 - Improve lookup of event publications in progress.

Instead of iterating over all publications currently in progress we now use a map to look them up by key.

Baseline
--------
Benchmark                        Mode  Cnt        Score      Error  Units
….inProgressPublicationsAccess  thrpt   50      312,155 ±    7,428  ops/s

Fixed
-----
Benchmark                        Mode  Cnt        Score      Error  Units
….inProgressPublicationsAccess  thrpt   50  2328732,504 ± 7809,092  ops/s
This commit is contained in:
Oliver Drotbohm
2025-04-18 12:56:52 +02:00
parent dc67a117d9
commit dc81a743f8
2 changed files with 48 additions and 12 deletions

View File

@@ -19,10 +19,9 @@ import java.time.Clock;
import java.time.Duration;
import java.time.Instant;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.function.Consumer;
import java.util.function.Predicate;
@@ -296,7 +295,7 @@ public class DefaultEventPublicationRegistry
*/
static class PublicationsInProgress implements Iterable<TargetEventPublication> {
private final Set<TargetEventPublication> publications = ConcurrentHashMap.newKeySet();
private final Map<Key, TargetEventPublication> publications = new ConcurrentHashMap<>();
/**
* Registers the given {@link TargetEventPublication} as currently processed.
@@ -308,7 +307,7 @@ public class DefaultEventPublicationRegistry
Assert.notNull(publication, "TargetEventPublication must not be null!");
publications.add(publication);
publications.put(new Key(publication), publication);
return publication;
}
@@ -325,8 +324,7 @@ public class DefaultEventPublicationRegistry
Assert.notNull(event, "Event must not be null!");
Assert.notNull(identifier, "PublicationTargetIdentifier must not be null!");
getPublication(event, identifier)
.ifPresent(publications::remove);
publications.remove(new Key(event, identifier));
}
/**
@@ -338,7 +336,7 @@ public class DefaultEventPublicationRegistry
Assert.notNull(publication, "TargetEventPublication must not be null!");
publications.remove(publication);
publications.remove(new Key(publication));
}
/**
@@ -354,9 +352,7 @@ public class DefaultEventPublicationRegistry
Assert.notNull(event, "Event must not be null!");
Assert.notNull(identifier, "PublicationTargetIdentifier must not be null!");
return publications.stream()
.filter(it -> it.isAssociatedWith(event, identifier))
.findFirst();
return Optional.ofNullable(publications.get(new Key(event, identifier)));
}
/*
@@ -365,7 +361,48 @@ public class DefaultEventPublicationRegistry
*/
@Override
public Iterator<TargetEventPublication> iterator() {
return new HashSet<>(publications).iterator();
return publications.values().iterator();
}
private record Key(Object event, PublicationTargetIdentifier identifier) {
public Key(TargetEventPublication publication) {
this(publication.getEvent(), publication.getTargetIdentifier());
}
/*
* (non-Javadoc)
* @see org.springframework.modulith.events.core.DefaultEventPublicationRegistry.PublicationsInProgress.Key#equals(java.lang.Object)
*/
@Override
public final boolean equals(Object obj) {
if (obj == this) {
return true;
}
if (!(obj instanceof Key that)) {
return false;
}
return this.event == that.event
&& this.identifier.equals(identifier);
}
/*
* (non-Javadoc)
* @see org.springframework.modulith.events.core.DefaultEventPublicationRegistry.PublicationsInProgress.Key#hashCode()
*/
@Override
public final int hashCode() {
int result = 7;
result += 31 * System.identityHashCode(event);
result += 31 * identifier.hashCode();
return result;
}
}
}
}

View File

@@ -97,7 +97,6 @@ class DefaultEventPublicationRegistryUnitTests {
assertThat(inProgress.getPublication(firstEvent, identifier)).containsSame(first);
assertThat(inProgress.getPublication(secondEvent, identifier)).containsSame(second);
}
private DefaultEventPublicationRegistry createRegistry(Instant instant) {