fix(version): forUpdate needed for versioning (#11328)

This commit is contained in:
david-leifker 2024-09-09 21:22:13 -05:00 committed by GitHub
parent cf49f80e77
commit c6eea1eec3
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 35 additions and 13 deletions

View File

@ -51,16 +51,30 @@ public interface AspectDao {
List<EntityAspect> getAspectsInRange( List<EntityAspect> getAspectsInRange(
@Nonnull Urn urn, Set<String> aspectNames, long startTimeMillis, long endTimeMillis); @Nonnull Urn urn, Set<String> aspectNames, long startTimeMillis, long endTimeMillis);
/**
* @param urn urn to fetch
* @param aspectName aspect to fetch
* @param forUpdate set to true if the result is used for versioning <a
* href="https://ebean.io/docs/query/option#forUpdate">link</a>
* @return
*/
@Nullable @Nullable
default EntityAspect getLatestAspect( default EntityAspect getLatestAspect(
@Nonnull final String urn, @Nonnull final String aspectName) { @Nonnull final String urn, @Nonnull final String aspectName, boolean forUpdate) {
return getLatestAspects(Map.of(urn, Set.of(aspectName))) return getLatestAspects(Map.of(urn, Set.of(aspectName)), forUpdate)
.getOrDefault(urn, Map.of()) .getOrDefault(urn, Map.of())
.getOrDefault(aspectName, null); .getOrDefault(aspectName, null);
} }
/**
* @param urnAspects urn/aspects to fetch
* @param forUpdate set to true if the result is used for versioning <a
* href="https://ebean.io/docs/query/option#forUpdate">link</a>
* @return the data
*/
@Nonnull @Nonnull
Map<String, Map<String, EntityAspect>> getLatestAspects(Map<String, Set<String>> urnAspects); Map<String, Map<String, EntityAspect>> getLatestAspects(
Map<String, Set<String>> urnAspects, boolean forUpdate);
void saveAspect( void saveAspect(
@Nullable Transaction tx, @Nullable Transaction tx,

View File

@ -849,7 +849,7 @@ public class EntityServiceImpl implements EntityService<ChangeItemImpl> {
final Map<String, Map<String, SystemAspect>> latestAspects = final Map<String, Map<String, SystemAspect>> latestAspects =
EntityUtils.toSystemAspects( EntityUtils.toSystemAspects(
opContext.getRetrieverContext().get(), opContext.getRetrieverContext().get(),
aspectDao.getLatestAspects(urnAspects)); aspectDao.getLatestAspects(urnAspects, true));
// read #2 (potentially) // read #2 (potentially)
final Map<String, Map<String, Long>> nextVersions = final Map<String, Map<String, Long>> nextVersions =
EntityUtils.calculateNextVersions(aspectDao, latestAspects, urnAspects); EntityUtils.calculateNextVersions(aspectDao, latestAspects, urnAspects);
@ -866,7 +866,7 @@ public class EntityServiceImpl implements EntityService<ChangeItemImpl> {
Map<String, Map<String, SystemAspect>> newLatestAspects = Map<String, Map<String, SystemAspect>> newLatestAspects =
EntityUtils.toSystemAspects( EntityUtils.toSystemAspects(
opContext.getRetrieverContext().get(), opContext.getRetrieverContext().get(),
aspectDao.getLatestAspects(updatedItems.getFirst())); aspectDao.getLatestAspects(updatedItems.getFirst(), true));
// merge // merge
updatedLatestAspects = AspectsBatch.merge(latestAspects, newLatestAspects); updatedLatestAspects = AspectsBatch.merge(latestAspects, newLatestAspects);
@ -2064,7 +2064,7 @@ public class EntityServiceImpl implements EntityService<ChangeItemImpl> {
EntityAspect latestKey = null; EntityAspect latestKey = null;
try { try {
latestKey = aspectDao.getLatestAspect(urn.toString(), keyAspectName); latestKey = aspectDao.getLatestAspect(urn.toString(), keyAspectName, false);
} catch (EntityNotFoundException e) { } catch (EntityNotFoundException e) {
log.warn("Entity to delete does not exist. {}", urn.toString()); log.warn("Entity to delete does not exist. {}", urn.toString());
} }
@ -2217,7 +2217,7 @@ public class EntityServiceImpl implements EntityService<ChangeItemImpl> {
(EntityAspect.EntitySystemAspect) (EntityAspect.EntitySystemAspect)
EntityUtils.toSystemAspect( EntityUtils.toSystemAspect(
opContext.getRetrieverContext().get(), opContext.getRetrieverContext().get(),
aspectDao.getLatestAspect(urn, aspectName)) aspectDao.getLatestAspect(urn, aspectName, false))
.orElse(null); .orElse(null);
// 1.1 If no latest exists, skip this aspect // 1.1 If no latest exists, skip this aspect

View File

@ -81,14 +81,15 @@ public class CassandraAspectDao implements AspectDao, AspectMigrationsDao {
} }
@Override @Override
public EntityAspect getLatestAspect(@Nonnull String urn, @Nonnull String aspectName) { public EntityAspect getLatestAspect(
@Nonnull String urn, @Nonnull String aspectName, boolean forUpdate) {
validateConnection(); validateConnection();
return getAspect(urn, aspectName, ASPECT_LATEST_VERSION); return getAspect(urn, aspectName, ASPECT_LATEST_VERSION);
} }
@Override @Override
public Map<String, Map<String, EntityAspect>> getLatestAspects( public Map<String, Map<String, EntityAspect>> getLatestAspects(
Map<String, Set<String>> urnAspects) { Map<String, Set<String>> urnAspects, boolean forUpdate) {
return urnAspects.entrySet().stream() return urnAspects.entrySet().stream()
.map( .map(
entry -> entry ->
@ -97,7 +98,8 @@ public class CassandraAspectDao implements AspectDao, AspectMigrationsDao {
entry.getValue().stream() entry.getValue().stream()
.map( .map(
aspectName -> { aspectName -> {
EntityAspect aspect = getLatestAspect(entry.getKey(), aspectName); EntityAspect aspect =
getLatestAspect(entry.getKey(), aspectName, forUpdate);
return aspect != null ? Map.entry(aspectName, aspect) : null; return aspect != null ? Map.entry(aspectName, aspect) : null;
}) })
.filter(Objects::nonNull) .filter(Objects::nonNull)

View File

@ -242,7 +242,7 @@ public class EbeanAspectDao implements AspectDao, AspectMigrationsDao {
@Override @Override
public Map<String, Map<String, EntityAspect>> getLatestAspects( public Map<String, Map<String, EntityAspect>> getLatestAspects(
@Nonnull Map<String, Set<String>> urnAspects) { @Nonnull Map<String, Set<String>> urnAspects, boolean forUpdate) {
validateConnection(); validateConnection();
List<EbeanAspectV2.PrimaryKey> keys = List<EbeanAspectV2.PrimaryKey> keys =
@ -256,7 +256,12 @@ public class EbeanAspectDao implements AspectDao, AspectMigrationsDao {
entry.getKey(), aspect, ASPECT_LATEST_VERSION))) entry.getKey(), aspect, ASPECT_LATEST_VERSION)))
.collect(Collectors.toList()); .collect(Collectors.toList());
List<EbeanAspectV2> results = _server.find(EbeanAspectV2.class).where().idIn(keys).findList(); final List<EbeanAspectV2> results;
if (forUpdate) {
results = _server.find(EbeanAspectV2.class).where().idIn(keys).forUpdate().findList();
} else {
results = _server.find(EbeanAspectV2.class).where().idIn(keys).findList();
}
return toUrnAspectMap(results); return toUrnAspectMap(results);
} }
@ -814,7 +819,8 @@ public class EbeanAspectDao implements AspectDao, AspectMigrationsDao {
return result; return result;
} }
List<EbeanAspectV2.PrimaryKey> dbResults = exp.endOr().findIds(); // forUpdate is required to avoid duplicate key violations
List<EbeanAspectV2.PrimaryKey> dbResults = exp.endOr().forUpdate().findIds();
for (EbeanAspectV2.PrimaryKey key : dbResults) { for (EbeanAspectV2.PrimaryKey key : dbResults) {
if (result.get(key.getUrn()).get(key.getAspect()) <= key.getVersion()) { if (result.get(key.getUrn()).get(key.getAspect()) <= key.getVersion()) {