Skip to content

Commit a8643c4

Browse files
committed
DATAES-799 - Support optimistic locking for full update scenario using seq_no + primary_term.
Make sure that usage of SeqNoPrimaryTerm together with @Version does not cause index rejections
1 parent a4be9df commit a8643c4

File tree

3 files changed

+44
-4
lines changed

3 files changed

+44
-4
lines changed

src/main/java/org/springframework/data/elasticsearch/core/AbstractElasticsearchTemplate.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -464,11 +464,13 @@ private <T> IndexQuery getIndexQuery(T entity) {
464464

465465
IndexQueryBuilder builder = new IndexQueryBuilder() //
466466
.withId(id) //
467-
.withVersion(getEntityVersion(entity)) //
468467
.withObject(entity);
469468
SeqNoPrimaryTerm seqNoPrimaryTerm = getEntitySeqNoPrimaryTerm(entity);
470469
if (seqNoPrimaryTerm != null) {
471470
builder.withSeqNoPrimaryTerm(seqNoPrimaryTerm);
471+
} else {
472+
// version cannot be used together with seq_no and primary_term
473+
builder.withVersion(getEntityVersion(entity));
472474
}
473475
return builder.build();
474476
}

src/test/java/org/springframework/data/elasticsearch/core/ElasticsearchTemplateTests.java

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3162,6 +3162,35 @@ void shouldThrowOptimisticLockingFailureExceptionWhenConcurrentUpdateOccursOnEnt
31623162
.isInstanceOf(OptimisticLockingFailureException.class);
31633163
}
31643164

3165+
@Test // DATAES-799
3166+
void shouldThrowOptimisticLockingFailureExceptionWhenConcurrentUpdateOccursOnVersionedEntityWithSeqNoPrimaryTermProperty() {
3167+
OptimisticAndVersionedEntity original = new OptimisticAndVersionedEntity();
3168+
original.setMessage("It's fine");
3169+
OptimisticAndVersionedEntity saved = operations.save(original);
3170+
3171+
OptimisticAndVersionedEntity forEdit1 = operations.get(saved.getId(), OptimisticAndVersionedEntity.class);
3172+
OptimisticAndVersionedEntity forEdit2 = operations.get(saved.getId(), OptimisticAndVersionedEntity.class);
3173+
3174+
forEdit1.setMessage("It'll be ok");
3175+
operations.save(forEdit1);
3176+
3177+
forEdit2.setMessage("It'll be great");
3178+
assertThatThrownBy(() -> operations.save(forEdit2))
3179+
.isInstanceOf(OptimisticLockingFailureException.class);
3180+
}
3181+
3182+
@Test // DATAES-799
3183+
void shouldAllowFullReplaceOfEntityWithBothSeqNoPrimaryTermAndVersion() {
3184+
OptimisticAndVersionedEntity original = new OptimisticAndVersionedEntity();
3185+
original.setMessage("It's fine");
3186+
OptimisticAndVersionedEntity saved = operations.save(original);
3187+
3188+
OptimisticAndVersionedEntity forEdit = operations.get(saved.getId(), OptimisticAndVersionedEntity.class);
3189+
3190+
forEdit.setMessage("It'll be ok");
3191+
operations.save(forEdit);
3192+
}
3193+
31653194
protected RequestFactory getRequestFactory() {
31663195
return ((AbstractElasticsearchTemplate) operations).getRequestFactory();
31673196
}
@@ -3333,4 +3362,13 @@ static class OptimisticEntity {
33333362
private String message;
33343363
private SeqNoPrimaryTerm seqNoPrimaryTerm;
33353364
}
3365+
3366+
@Data
3367+
@Document(indexName = "test-index-optimistic-and-versioned-entity-template")
3368+
static class OptimisticAndVersionedEntity {
3369+
@Id private String id;
3370+
private String message;
3371+
private SeqNoPrimaryTerm seqNoPrimaryTerm;
3372+
@Version private Long version;
3373+
}
33363374
}

src/test/java/org/springframework/data/elasticsearch/core/RequestFactoryTests.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ class RequestFactoryTests {
6767
@BeforeAll
6868
static void setUpAll() {
6969
SimpleElasticsearchMappingContext mappingContext = new SimpleElasticsearchMappingContext();
70-
mappingContext.setInitialEntitySet(new HashSet<>(Arrays.asList(Person.class, EntityWithSeqNoAndPrimaryTerm.class)));
70+
mappingContext.setInitialEntitySet(new HashSet<>(Arrays.asList(Person.class, EntityWithSeqNoPrimaryTerm.class)));
7171
mappingContext.afterPropertiesSet();
7272

7373
converter = new MappingElasticsearchConverter(mappingContext, new GenericConversionService());
@@ -184,7 +184,7 @@ void shouldNotRequestSeqNoAndPrimartyTermViaSearchRequestWhenEntityClassDoesNotC
184184
void shouldRequestSeqNoAndPrimartyTermViaSearchRequestWhenEntityClassContainsSeqNoPrimaryTermProperty() {
185185
Query query = new NativeSearchQueryBuilder().build();
186186

187-
SearchRequest request = requestFactory.searchRequest(query, EntityWithSeqNoAndPrimaryTerm.class,
187+
SearchRequest request = requestFactory.searchRequest(query, EntityWithSeqNoPrimaryTerm.class,
188188
IndexCoordinates.of("seqNoPrimaryTerm"));
189189

190190
assertThat(request.source().seqNoAndPrimaryTerm()).isTrue();
@@ -205,7 +205,7 @@ static class Person {
205205
@Nullable @Field(name = "current-location") GeoPoint location;
206206
}
207207

208-
static class EntityWithSeqNoAndPrimaryTerm {
208+
static class EntityWithSeqNoPrimaryTerm {
209209
@Nullable private SeqNoPrimaryTerm seqNoPrimaryTerm;
210210
}
211211
}

0 commit comments

Comments
 (0)