Add doc's sequence number + primary term to GetResult and use it for updates (#36680)

This commit adds the last sequence number and primary term of the last operation that have
modified a document to `GetResult` and uses it to power the Update API.

Relates #36148 
Relates #10708
This commit is contained in:
Boaz Leskes 2018-12-17 15:22:13 +01:00 committed by GitHub
parent a181a25226
commit e356b8cb95
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 262 additions and 119 deletions

View File

@ -63,6 +63,8 @@ Returns this:
"_type": "_doc",
"_id": "my_id",
"_version": 1,
"_seq_no": 22,
"_primary_term": 1,
"_source": {
"data": "e1xydGYxXGFuc2kNCkxvcmVtIGlwc3VtIGRvbG9yIHNpdCBhbWV0DQpccGFyIH0=",
"attachment": {
@ -74,7 +76,7 @@ Returns this:
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
To specify only some fields to be extracted:
@ -146,6 +148,8 @@ Returns this:
"_type": "_doc",
"_id": "my_id",
"_version": 1,
"_seq_no": 35,
"_primary_term": 1,
"_source": {
"data": "e1xydGYxXGFuc2kNCkxvcmVtIGlwc3VtIGRvbG9yIHNpdCBhbWV0DQpccGFyIH0=",
"attachment": {
@ -157,7 +161,7 @@ Returns this:
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
[source,js]
@ -194,6 +198,8 @@ Returns this:
"_type": "_doc",
"_id": "my_id_2",
"_version": 1,
"_seq_no": 40,
"_primary_term": 1,
"_source": {
"data": "e1xydGYxXGFuc2kNCkxvcmVtIGlwc3VtIGRvbG9yIHNpdCBhbWV0DQpccGFyIH0=",
"max_size": 5,
@ -206,7 +212,7 @@ Returns this:
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
[[ingest-attachment-with-arrays]]
@ -285,6 +291,8 @@ Returns this:
"_type" : "_doc",
"_id" : "my_id",
"_version" : 1,
"_seq_no" : 50,
"_primary_term" : 1,
"found" : true,
"_source" : {
"attachments" : [
@ -312,7 +320,7 @@ Returns this:
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no" : \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
Note that the `target_field` needs to be set, otherwise the

View File

@ -75,6 +75,8 @@ Which returns:
"_type": "_doc",
"_id": "my_id",
"_version": 1,
"_seq_no": 55,
"_primary_term": 1,
"_source": {
"ip": "8.8.8.8",
"geoip": {
@ -85,7 +87,7 @@ Which returns:
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term":1/"_primary_term" : $body._primary_term/]
Here is an example that uses the default country database and adds the
geographical information to the `geo` field based on the `ip` field`. Note that
@ -124,6 +126,8 @@ returns this:
"_type": "_doc",
"_id": "my_id",
"_version": 1,
"_seq_no": 65,
"_primary_term": 1,
"_source": {
"ip": "8.8.8.8",
"geo": {
@ -133,7 +137,7 @@ returns this:
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
Not all IP addresses find geo information from the database, When this
@ -174,13 +178,15 @@ Which returns:
"_type" : "_doc",
"_id" : "my_id",
"_version" : 1,
"_seq_no" : 71,
"_primary_term": 1,
"found" : true,
"_source" : {
"ip" : "80.231.5.0"
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no" : \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
[[ingest-geoip-mappings-note]]
===== Recognizing Location as a Geopoint

View File

@ -57,6 +57,8 @@ Which returns
"_type": "_doc",
"_id": "my_id",
"_version": 1,
"_seq_no": 22,
"_primary_term": 1,
"_source": {
"agent": "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_10_5) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/51.0.2704.103 Safari/537.36",
"user_agent": {
@ -73,7 +75,7 @@ Which returns
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term": 1/"_primary_term" : $body._primary_term/]
===== Using a custom regex file
To use a custom regex file for parsing the user agents, that file has to be put into the `config/ingest-user-agent` directory and

View File

@ -21,6 +21,8 @@ The result of the above get operation is:
"_type" : "_doc",
"_id" : "0",
"_version" : 1,
"_seq_no" : 10,
"_primary_term" : 1,
"found": true,
"_source" : {
"user" : "kimchy",
@ -30,7 +32,7 @@ The result of the above get operation is:
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no" : \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
The above result includes the `_index`, `_type`, `_id` and `_version`
of the document we wish to retrieve, including the actual `_source`
@ -156,6 +158,8 @@ The result of the above get operation is:
"_type": "_doc",
"_id": "1",
"_version": 1,
"_seq_no" : 22,
"_primary_term" : 1,
"found": true,
"fields": {
"tags": [
@ -164,7 +168,7 @@ The result of the above get operation is:
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no" : \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
Field values fetched from the document itself are always returned as an array.
@ -199,6 +203,8 @@ The result of the above get operation is:
"_type": "_doc",
"_id": "2",
"_version": 1,
"_seq_no" : 13,
"_primary_term" : 1,
"_routing": "user1",
"found": true,
"fields": {
@ -208,7 +214,7 @@ The result of the above get operation is:
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no" : \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
Also only leaf fields can be returned via the `stored_field` option. So object fields can't be returned and such requests
will fail.

View File

@ -870,13 +870,15 @@ which will return:
"_index": "test2",
"_type": "_doc",
"_version": 1,
"_seq_no": 44,
"_primary_term": 1,
"_source": {
"text": "words words",
"tag": "foo"
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term": 1/"_primary_term" : $body._primary_term/]
[float]
[[docs-reindex-slice]]

View File

@ -421,7 +421,7 @@ And the response:
"_primary_term" : 1
}
--------------------------------------------------
// TESTRESPONSE[s/"_seq_no" : 0/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
// TESTRESPONSE[s/"_seq_no" : \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
From the above, we can see that a new customer document was successfully created inside the customer index. The document also has an internal id of 1 which we specified at index time.
@ -445,11 +445,13 @@ And the response:
"_type" : "_doc",
"_id" : "1",
"_version" : 1,
"_seq_no" : 25,
"_primary_term" : 1,
"found" : true,
"_source" : { "name": "John Doe" }
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no" : \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
Nothing out of the ordinary here other than a field, `found`, stating that we found a document with the requested ID 1 and another field, `_source`, which returns the full JSON document that we indexed from the previous step.

View File

@ -730,13 +730,15 @@ GET test/_doc/2
"_type": "_doc",
"_id": "2",
"_version": 1,
"_seq_no": 22,
"_primary_term": 1,
"found": true,
"_source": {
"foo": "bar"
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term": 1/"_primary_term" : $body._primary_term/]
////
The source document can also use dot delimited fields to represent nested fields.
@ -967,6 +969,8 @@ GET test/_doc/2
"_type": "_doc",
"_id": "2",
"_version": 1,
"_seq_no": 34,
"_primary_term": 1,
"found": true,
"_source": {
"tags": [
@ -976,7 +980,7 @@ GET test/_doc/2
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
////
@ -1088,6 +1092,8 @@ GET test/_doc/1
"_type": "_doc",
"_id": "1",
"_version": 1,
"_seq_no": 60,
"_primary_term": 1,
"found": true,
"_source": {
"href": {
@ -1097,7 +1103,7 @@ GET test/_doc/1
}
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
Regular expressions can be expensive and should be avoided if viable
@ -1548,11 +1554,11 @@ PUT /myindex/_doc/1?pipeline=monthlyindex
"successful" : 1,
"failed" : 0
},
"_seq_no" : 0,
"_seq_no" : 55,
"_primary_term" : 1
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no" : \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
The above request will not index this document into the `myindex` index, but into the `myindex-2016-04-01` index because
@ -2787,11 +2793,11 @@ Response from the index request:
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_seq_no": 66,
"_primary_term": 1,
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
Indexed document:
@ -2963,11 +2969,11 @@ The response from the above index request:
"successful": 1,
"failed": 0
},
"_seq_no": 0,
"_seq_no": 89,
"_primary_term": 1,
}
--------------------------------------------------
// TESTRESPONSE
// TESTRESPONSE[s/"_seq_no": \d+/"_seq_no" : $body._seq_no/ s/"_primary_term" : 1/"_primary_term" : $body._primary_term/]
In the above response, you can see that our document was actually indexed into `my_index` instead of
`any_index`. This type of manipulation is often convenient in pipelines that have various branches of transformation,

View File

@ -54,6 +54,7 @@ import java.util.List;
import java.util.Map;
import java.util.Set;
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
import static org.hamcrest.Matchers.equalTo;
public class PercolateQueryBuilderTests extends AbstractQueryTestCase<PercolateQueryBuilder> {
@ -152,12 +153,13 @@ public class PercolateQueryBuilderTests extends AbstractQueryTestCase<PercolateQ
assertThat(getRequest.version(), Matchers.equalTo(indexedDocumentVersion));
if (indexedDocumentExists) {
return new GetResponse(
new GetResult(indexedDocumentIndex, indexedDocumentType, indexedDocumentId, 0L, true,
new GetResult(indexedDocumentIndex, indexedDocumentType, indexedDocumentId, 0, 1, 0L, true,
documentSource.iterator().next(), Collections.emptyMap())
);
} else {
return new GetResponse(
new GetResult(indexedDocumentIndex, indexedDocumentType, indexedDocumentId, -1, false, null, Collections.emptyMap())
new GetResult(indexedDocumentIndex, indexedDocumentType, indexedDocumentId, UNASSIGNED_SEQ_NO, 0, -1,
false, null, Collections.emptyMap())
);
}
}

View File

@ -307,6 +307,7 @@ public class TransportShardBulkAction extends TransportWriteAction<BulkShardRequ
final Tuple<XContentType, Map<String, Object>> sourceAndContent =
XContentHelper.convertToMap(indexSourceAsBytes, true, updateIndexRequest.getContentType());
updateResponse.setGetResult(UpdateHelper.extractGetResult(updateRequest, concreteIndex,
indexResponse.getSeqNo(), indexResponse.getPrimaryTerm(),
indexResponse.getVersion(), sourceAndContent.v2(), sourceAndContent.v1(), indexSourceAsBytes));
}
} else if (translatedResult == DocWriteResponse.Result.DELETED) {
@ -315,7 +316,8 @@ public class TransportShardBulkAction extends TransportWriteAction<BulkShardRequ
deleteResponse.getType(), deleteResponse.getId(), deleteResponse.getSeqNo(), deleteResponse.getPrimaryTerm(),
deleteResponse.getVersion(), deleteResponse.getResult());
final GetResult getResult = UpdateHelper.extractGetResult(updateRequest, concreteIndex, deleteResponse.getVersion(),
final GetResult getResult = UpdateHelper.extractGetResult(updateRequest, concreteIndex,
deleteResponse.getSeqNo(), deleteResponse.getPrimaryTerm(), deleteResponse.getVersion(),
translate.updatedSourceAsMap(), translate.updateSourceContentType(), null);
updateResponse.setGetResult(getResult);

View File

@ -90,6 +90,20 @@ public class GetResponse extends ActionResponse implements Iterable<DocumentFiel
return getResult.getVersion();
}
/**
* The sequence number assigned to the last operation to have changed this document, if found.
*/
public long getSeqNo() {
return getResult.getSeqNo();
}
/**
* The primary term of the last primary that has changed this document, if found.
*/
public long getPrimaryTerm() {
return getResult.getPrimaryTerm();
}
/**
* The source of the document if exists.
*/

View File

@ -19,6 +19,7 @@
package org.elasticsearch.action.update;
import org.elasticsearch.ResourceAlreadyExistsException;
import org.elasticsearch.action.ActionListener;
import org.elasticsearch.action.ActionRunnable;
import org.elasticsearch.action.RoutingMissingException;
@ -50,7 +51,6 @@ import org.elasticsearch.index.IndexService;
import org.elasticsearch.index.engine.VersionConflictEngineException;
import org.elasticsearch.index.shard.IndexShard;
import org.elasticsearch.index.shard.ShardId;
import org.elasticsearch.ResourceAlreadyExistsException;
import org.elasticsearch.indices.IndicesService;
import org.elasticsearch.tasks.Task;
import org.elasticsearch.threadpool.ThreadPool;
@ -185,8 +185,9 @@ public class TransportUpdateAction extends TransportInstanceSingleOperationActio
if (request.fetchSource() != null && request.fetchSource().fetchSource()) {
Tuple<XContentType, Map<String, Object>> sourceAndContent =
XContentHelper.convertToMap(upsertSourceBytes, true, upsertRequest.getContentType());
update.setGetResult(UpdateHelper.extractGetResult(request, request.concreteIndex(), response.getVersion(),
sourceAndContent.v2(), sourceAndContent.v1(), upsertSourceBytes));
update.setGetResult(UpdateHelper.extractGetResult(request, request.concreteIndex(),
response.getSeqNo(), response.getPrimaryTerm(), response.getVersion(), sourceAndContent.v2(),
sourceAndContent.v1(), upsertSourceBytes));
} else {
update.setGetResult(null);
}
@ -205,7 +206,8 @@ public class TransportUpdateAction extends TransportInstanceSingleOperationActio
UpdateResponse update = new UpdateResponse(response.getShardInfo(), response.getShardId(),
response.getType(), response.getId(), response.getSeqNo(), response.getPrimaryTerm(),
response.getVersion(), response.getResult());
update.setGetResult(UpdateHelper.extractGetResult(request, request.concreteIndex(), response.getVersion(),
update.setGetResult(UpdateHelper.extractGetResult(request, request.concreteIndex(),
response.getSeqNo(), response.getPrimaryTerm(), response.getVersion(),
result.updatedSourceAsMap(), result.updateSourceContentType(), indexSourceBytes));
update.setForcedRefresh(response.forcedRefresh());
listener.onResponse(update);
@ -216,10 +218,11 @@ public class TransportUpdateAction extends TransportInstanceSingleOperationActio
DeleteRequest deleteRequest = result.action();
client.bulk(toSingleItemBulkRequest(deleteRequest), wrapBulkResponse(
ActionListener.<DeleteResponse>wrap(response -> {
UpdateResponse update = new UpdateResponse(response.getShardInfo(), response.getShardId(),
response.getType(), response.getId(), response.getSeqNo(), response.getPrimaryTerm(),
response.getVersion(), response.getResult());
update.setGetResult(UpdateHelper.extractGetResult(request, request.concreteIndex(), response.getVersion(),
UpdateResponse update = new UpdateResponse(response.getShardInfo(), response.getShardId(), response.getType(),
response.getId(), response.getSeqNo(), response.getPrimaryTerm(), response.getVersion(),
response.getResult());
update.setGetResult(UpdateHelper.extractGetResult(request, request.concreteIndex(),
response.getSeqNo(), response.getPrimaryTerm(), response.getVersion(),
result.updatedSourceAsMap(), result.updateSourceContentType(), null));
update.setForcedRefresh(response.forcedRefresh());
listener.onResponse(update);

View File

@ -209,8 +209,8 @@ public class UpdateHelper {
if (detectNoop && noop) {
UpdateResponse update = new UpdateResponse(shardId, getResult.getType(), getResult.getId(),
getResult.getVersion(), DocWriteResponse.Result.NOOP);
update.setGetResult(extractGetResult(request, request.index(), getResult.getVersion(), updatedSourceAsMap,
updateSourceContentType, getResult.internalSourceRef()));
update.setGetResult(extractGetResult(request, request.index(), getResult.getSeqNo(), getResult.getPrimaryTerm(),
getResult.getVersion(), updatedSourceAsMap, updateSourceContentType, getResult.internalSourceRef()));
return new Result(update, DocWriteResponse.Result.NOOP, updatedSourceAsMap, updateSourceContentType);
} else {
final IndexRequest finalIndexRequest = Requests.indexRequest(request.index())
@ -270,10 +270,9 @@ public class UpdateHelper {
// If it was neither an INDEX or DELETE operation, treat it as a noop
UpdateResponse update = new UpdateResponse(shardId, getResult.getType(), getResult.getId(),
getResult.getVersion(), DocWriteResponse.Result.NOOP);
update.setGetResult(extractGetResult(request, request.index(), getResult.getVersion(), updatedSourceAsMap,
updateSourceContentType, getResult.internalSourceRef()));
update.setGetResult(extractGetResult(request, request.index(), getResult.getSeqNo(), getResult.getPrimaryTerm(),
getResult.getVersion(), updatedSourceAsMap, updateSourceContentType, getResult.internalSourceRef()));
return new Result(update, DocWriteResponse.Result.NOOP, updatedSourceAsMap, updateSourceContentType);
}
}
@ -293,7 +292,7 @@ public class UpdateHelper {
/**
* Applies {@link UpdateRequest#fetchSource()} to the _source of the updated document to be returned in a update response.
*/
public static GetResult extractGetResult(final UpdateRequest request, String concreteIndex, long version,
public static GetResult extractGetResult(final UpdateRequest request, String concreteIndex, long seqNo, long primaryTerm, long version,
final Map<String, Object> source, XContentType sourceContentType,
@Nullable final BytesReference sourceAsBytes) {
if (request.fetchSource() == null || request.fetchSource().fetchSource() == false) {
@ -318,7 +317,8 @@ public class UpdateHelper {
}
// TODO when using delete/none, we can still return the source as bytes by generating it (using the sourceContentType)
return new GetResult(concreteIndex, request.type(), request.id(), version, true, sourceFilteredAsBytes, Collections.emptyMap());
return new GetResult(concreteIndex, request.type(), request.id(), seqNo, primaryTerm, version, true, sourceFilteredAsBytes,
Collections.emptyMap());
}
public static class Result {

View File

@ -162,8 +162,9 @@ public class UpdateResponse extends DocWriteResponse {
update = new UpdateResponse(shardId, type, id, version, result);
}
if (getResult != null) {
update.setGetResult(new GetResult(update.getIndex(), update.getType(), update.getId(), update.getVersion(),
getResult.isExists(),getResult.internalSourceRef(), getResult.getFields()));
update.setGetResult(new GetResult(update.getIndex(), update.getType(), update.getId(),
getResult.getSeqNo(), getResult.getPrimaryTerm(), update.getVersion(),
getResult.isExists(), getResult.internalSourceRef(), getResult.getFields()));
}
update.setForcedRefresh(forcedRefresh);
return update;

View File

@ -20,6 +20,7 @@
package org.elasticsearch.index.get;
import org.elasticsearch.ElasticsearchParseException;
import org.elasticsearch.Version;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.compress.CompressorFactory;
@ -33,6 +34,7 @@ import org.elasticsearch.common.xcontent.XContentHelper;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.index.mapper.IgnoredFieldMapper;
import org.elasticsearch.index.mapper.SourceFieldMapper;
import org.elasticsearch.index.seqno.SequenceNumbers;
import org.elasticsearch.search.lookup.SourceLookup;
import java.io.IOException;
@ -53,6 +55,8 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
public static final String _TYPE = "_type";
public static final String _ID = "_id";
private static final String _VERSION = "_version";
private static final String _SEQ_NO = "_seq_no";
private static final String _PRIMARY_TERM = "_primary_term";
private static final String FOUND = "found";
private static final String FIELDS = "fields";
@ -60,6 +64,8 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
private String type;
private String id;
private long version;
private long seqNo;
private long primaryTerm;
private boolean exists;
private Map<String, DocumentField> fields;
private Map<String, Object> sourceAsMap;
@ -69,11 +75,17 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
GetResult() {
}
public GetResult(String index, String type, String id, long version, boolean exists, BytesReference source,
Map<String, DocumentField> fields) {
public GetResult(String index, String type, String id, long seqNo, long primaryTerm, long version, boolean exists,
BytesReference source, Map<String, DocumentField> fields) {
this.index = index;
this.type = type;
this.id = id;
this.seqNo = seqNo;
this.primaryTerm = primaryTerm;
assert (seqNo == SequenceNumbers.UNASSIGNED_SEQ_NO && primaryTerm == 0) || (seqNo >= 0 && primaryTerm >= 1) :
"seqNo: " + seqNo + " primaryTerm: " + primaryTerm;
assert exists || (seqNo == SequenceNumbers.UNASSIGNED_SEQ_NO && primaryTerm == 0) :
"doc not found but seqNo/primaryTerm are set";
this.version = version;
this.exists = exists;
this.source = source;
@ -118,6 +130,20 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
return version;
}
/**
* The sequence number assigned to the last operation to have changed this document, if found.
*/
public long getSeqNo() {
return seqNo;
}
/**
* The primary term of the last primary that has changed this document, if found.
*/
public long getPrimaryTerm() {
return primaryTerm;
}
/**
* The source of the document if exists.
*/
@ -213,6 +239,11 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
}
public XContentBuilder toXContentEmbedded(XContentBuilder builder, Params params) throws IOException {
if (seqNo != SequenceNumbers.UNASSIGNED_SEQ_NO) { // seqNo may not be assigned if read from an old node
builder.field(_SEQ_NO, seqNo);
builder.field(_PRIMARY_TERM, primaryTerm);
}
List<DocumentField> metaFields = new ArrayList<>();
List<DocumentField> otherFields = new ArrayList<>();
if (fields != null && !fields.isEmpty()) {
@ -282,6 +313,8 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
String currentFieldName = parser.currentName();
long version = -1;
long seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
long primaryTerm = 0;
Boolean found = null;
BytesReference source = null;
Map<String, DocumentField> fields = new HashMap<>();
@ -297,6 +330,10 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
id = parser.text();
} else if (_VERSION.equals(currentFieldName)) {
version = parser.longValue();
} else if (_SEQ_NO.equals(currentFieldName)) {
seqNo = parser.longValue();
} else if (_PRIMARY_TERM.equals(currentFieldName)) {
primaryTerm = parser.longValue();
} else if (FOUND.equals(currentFieldName)) {
found = parser.booleanValue();
} else {
@ -326,7 +363,7 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
}
}
}
return new GetResult(index, type, id, version, found, source, fields);
return new GetResult(index, type, id, seqNo, primaryTerm, version, found, source, fields);
}
public static GetResult fromXContent(XContentParser parser) throws IOException {
@ -347,6 +384,13 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
index = in.readString();
type = in.readOptionalString();
id = in.readString();
if (in.getVersion().onOrAfter(Version.V_7_0_0)) {
seqNo = in.readZLong();
primaryTerm = in.readVLong();
} else {
seqNo = SequenceNumbers.UNASSIGNED_SEQ_NO;
primaryTerm = 0L;
}
version = in.readLong();
exists = in.readBoolean();
if (exists) {
@ -372,6 +416,10 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
out.writeString(index);
out.writeOptionalString(type);
out.writeString(id);
if (out.getVersion().onOrAfter(Version.V_7_0_0)) {
out.writeZLong(seqNo);
out.writeVLong(primaryTerm);
}
out.writeLong(version);
out.writeBoolean(exists);
if (exists) {
@ -397,6 +445,8 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
}
GetResult getResult = (GetResult) o;
return version == getResult.version &&
seqNo == getResult.seqNo &&
primaryTerm == getResult.primaryTerm &&
exists == getResult.exists &&
Objects.equals(index, getResult.index) &&
Objects.equals(type, getResult.type) &&
@ -407,7 +457,7 @@ public class GetResult implements Streamable, Iterable<DocumentField>, ToXConten
@Override
public int hashCode() {
return Objects.hash(version, exists, index, type, id, fields, sourceAsMap());
return Objects.hash(version, seqNo, primaryTerm, exists, index, type, id, fields, sourceAsMap());
}
@Override

View File

@ -45,6 +45,7 @@ import org.elasticsearch.index.mapper.MapperService;
import org.elasticsearch.index.mapper.RoutingFieldMapper;
import org.elasticsearch.index.mapper.SourceFieldMapper;
import org.elasticsearch.index.mapper.Uid;
import org.elasticsearch.index.seqno.SequenceNumbers;
import org.elasticsearch.index.shard.AbstractIndexShardComponent;
import org.elasticsearch.index.shard.IndexShard;
import org.elasticsearch.search.fetch.subphase.FetchSourceContext;
@ -112,7 +113,7 @@ public final class ShardGetService extends AbstractIndexShardComponent {
public GetResult get(Engine.GetResult engineGetResult, String id, String type,
String[] fields, FetchSourceContext fetchSourceContext) {
if (!engineGetResult.exists()) {
return new GetResult(shardId.getIndexName(), type, id, -1, false, null, null);
return new GetResult(shardId.getIndexName(), type, id, SequenceNumbers.UNASSIGNED_SEQ_NO, 0, -1, false, null, null);
}
currentMetric.inc();
@ -168,7 +169,7 @@ public final class ShardGetService extends AbstractIndexShardComponent {
}
if (get == null || get.exists() == false) {
return new GetResult(shardId.getIndexName(), type, id, -1, false, null, null);
return new GetResult(shardId.getIndexName(), type, id, SequenceNumbers.UNASSIGNED_SEQ_NO, 0, -1, false, null, null);
}
try {
@ -233,7 +234,8 @@ public final class ShardGetService extends AbstractIndexShardComponent {
}
}
return new GetResult(shardId.getIndexName(), type, id, get.version(), get.exists(), source, fields);
return new GetResult(shardId.getIndexName(), type, id, get.docIdAndVersion().seqNo, get.docIdAndVersion().primaryTerm,
get.version(), get.exists(), source, fields);
}
private static FieldsVisitor buildFieldsVisitors(String[] fields, FetchSourceContext fetchSourceContext) {

View File

@ -65,7 +65,7 @@ public class ExplainResponseTests extends AbstractStreamableXContentTestCase<Exp
GetResult getResult = new GetResult(randomAlphaOfLengthBetween(3, 10),
randomAlphaOfLengthBetween(3, 10),
randomAlphaOfLengthBetween(3, 10),
randomNonNegativeLong(),
0, 1, randomNonNegativeLong(),
true,
RandomObjects.randomSource(random()),
singletonMap(fieldName, new DocumentField(fieldName, values)));
@ -83,7 +83,7 @@ public class ExplainResponseTests extends AbstractStreamableXContentTestCase<Exp
String id = "1";
boolean exist = true;
Explanation explanation = Explanation.match(1.0f, "description", Collections.emptySet());
GetResult getResult = new GetResult(null, null, null, -1, true, new BytesArray("{ \"field1\" : " +
GetResult getResult = new GetResult(null, null, null, 0, 1, -1, true, new BytesArray("{ \"field1\" : " +
"\"value1\", \"field2\":\"value2\"}"), singletonMap("field1", new DocumentField("field1",
singletonList("value1"))));
ExplainResponse response = new ExplainResponse(index, type, id, exist, explanation, getResult);
@ -105,6 +105,8 @@ public class ExplainResponseTests extends AbstractStreamableXContentTestCase<Exp
" \"details\":[]\n" +
" },\n" +
" \"get\":{\n" +
" \"_seq_no\":0," +
" \"_primary_term\":1," +
" \"found\":true,\n" +
" \"_source\":{\n" +
" \"field1\":\"value1\",\n" +

View File

@ -39,6 +39,7 @@ import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
import static org.elasticsearch.index.get.GetResultTests.copyGetResult;
import static org.elasticsearch.index.get.GetResultTests.mutateGetResult;
import static org.elasticsearch.index.get.GetResultTests.randomGetResult;
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode;
import static org.elasticsearch.test.XContentTestUtils.insertRandomFields;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
@ -91,26 +92,28 @@ public class GetResponseTests extends ESTestCase {
public void testToXContent() {
{
GetResponse getResponse = new GetResponse(new GetResult("index", "type", "id", 1, true, new BytesArray("{ \"field1\" : " +
GetResponse getResponse = new GetResponse(new GetResult("index", "type", "id", 0, 1, 1, true, new BytesArray("{ \"field1\" : " +
"\"value1\", \"field2\":\"value2\"}"), Collections.singletonMap("field1", new DocumentField("field1",
Collections.singletonList("value1")))));
String output = Strings.toString(getResponse);
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":1,\"found\":true,\"_source\":{ \"field1\" " +
": \"value1\", \"field2\":\"value2\"},\"fields\":{\"field1\":[\"value1\"]}}", output);
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":1,\"_seq_no\":0,\"_primary_term\":1," +
"\"found\":true,\"_source\":{ \"field1\" : \"value1\", \"field2\":\"value2\"},\"fields\":{\"field1\":[\"value1\"]}}",
output);
}
{
GetResponse getResponse = new GetResponse(new GetResult("index", "type", "id", 1, false, null, null));
GetResponse getResponse = new GetResponse(new GetResult("index", "type", "id", UNASSIGNED_SEQ_NO, 0, 1, false, null, null));
String output = Strings.toString(getResponse);
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"found\":false}", output);
}
}
public void testToString() {
GetResponse getResponse = new GetResponse(
new GetResult("index", "type", "id", 1, true, new BytesArray("{ \"field1\" : " + "\"value1\", \"field2\":\"value2\"}"),
GetResponse getResponse = new GetResponse(new GetResult("index", "type", "id", 0, 1, 1, true,
new BytesArray("{ \"field1\" : " + "\"value1\", \"field2\":\"value2\"}"),
Collections.singletonMap("field1", new DocumentField("field1", Collections.singletonList("value1")))));
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":1,\"found\":true,\"_source\":{ \"field1\" "
+ ": \"value1\", \"field2\":\"value2\"},\"fields\":{\"field1\":[\"value1\"]}}", getResponse.toString());
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":1,\"_seq_no\":0,\"_primary_term\":1," +
"\"found\":true,\"_source\":{ \"field1\" : \"value1\", \"field2\":\"value2\"},\"fields\":{\"field1\":[\"value1\"]}}",
getResponse.toString());
}
public void testEqualsAndHashcode() {
@ -119,7 +122,8 @@ public class GetResponseTests extends ESTestCase {
}
public void testFromXContentThrowsParsingException() throws IOException {
GetResponse getResponse = new GetResponse(new GetResult(null, null, null, randomIntBetween(1, 5), randomBoolean(), null, null));
GetResponse getResponse =
new GetResponse(new GetResult(null, null, null, UNASSIGNED_SEQ_NO, 0, randomIntBetween(1, 5), randomBoolean(), null, null));
XContentType xContentType = randomFrom(XContentType.values());
BytesReference originalBytes = toShuffledXContent(getResponse, xContentType, ToXContent.EMPTY_PARAMS, randomBoolean());

View File

@ -70,7 +70,7 @@ public class MultiGetResponseTests extends ESTestCase {
for (int i = 0; i < items.length; i++) {
if (randomBoolean()) {
items[i] = new MultiGetItemResponse(new GetResponse(new GetResult(
randomAlphaOfLength(4), randomAlphaOfLength(4), randomAlphaOfLength(4), randomNonNegativeLong(),
randomAlphaOfLength(4), randomAlphaOfLength(4), randomAlphaOfLength(4), 0, 1, randomNonNegativeLong(),
true, null, null
)), null);
} else {

View File

@ -60,6 +60,7 @@ import java.util.function.Function;
import static java.util.Collections.emptyMap;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
import static org.elasticsearch.script.MockScriptEngine.mockInlineScript;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
import static org.hamcrest.CoreMatchers.hasItems;
@ -359,7 +360,7 @@ public class UpdateRequestTests extends ESTestCase {
.scriptedUpsert(true);
long nowInMillis = randomNonNegativeLong();
// We simulate that the document is not existing yet
GetResult getResult = new GetResult("test", "type1", "2", 0, false, null, null);
GetResult getResult = new GetResult("test", "type1", "2", UNASSIGNED_SEQ_NO, 0, 0, false, null, null);
UpdateHelper.Result result = updateHelper.prepare(new ShardId("test", "_na_", 0), updateRequest, getResult, () -> nowInMillis);
Streamable action = result.action();
assertThat(action, instanceOf(IndexRequest.class));
@ -372,7 +373,7 @@ public class UpdateRequestTests extends ESTestCase {
.script(mockInlineScript("ctx._timestamp = ctx._now"))
.scriptedUpsert(true);
// We simulate that the document is not existing yet
GetResult getResult = new GetResult("test", "type1", "2", 0, true, new BytesArray("{}"), null);
GetResult getResult = new GetResult("test", "type1", "2", 0, 1, 0, true, new BytesArray("{}"), null);
UpdateHelper.Result result = updateHelper.prepare(new ShardId("test", "_na_", 0), updateRequest, getResult, () -> 42L);
Streamable action = result.action();
assertThat(action, instanceOf(IndexRequest.class));
@ -381,7 +382,7 @@ public class UpdateRequestTests extends ESTestCase {
public void testIndexTimeout() {
final GetResult getResult =
new GetResult("test", "type", "1", 0, true, new BytesArray("{\"f\":\"v\"}"), null);
new GetResult("test", "type", "1", 0, 1, 0, true, new BytesArray("{\"f\":\"v\"}"), null);
final UpdateRequest updateRequest =
new UpdateRequest("test", "type", "1")
.script(mockInlineScript("return"))
@ -391,7 +392,7 @@ public class UpdateRequestTests extends ESTestCase {
public void testDeleteTimeout() {
final GetResult getResult =
new GetResult("test", "type", "1", 0, true, new BytesArray("{\"f\":\"v\"}"), null);
new GetResult("test", "type", "1", 0, 1, 0, true, new BytesArray("{\"f\":\"v\"}"), null);
final UpdateRequest updateRequest =
new UpdateRequest("test", "type", "1")
.script(mockInlineScript("ctx.op = delete"))
@ -402,7 +403,7 @@ public class UpdateRequestTests extends ESTestCase {
public void testUpsertTimeout() throws IOException {
final boolean exists = randomBoolean();
final BytesReference source = exists ? new BytesArray("{\"f\":\"v\"}") : null;
final GetResult getResult = new GetResult("test", "type", "1", 0, exists, source, null);
final GetResult getResult = new GetResult("test", "type", "1", UNASSIGNED_SEQ_NO, 0, 0, exists, source, null);
final XContentBuilder sourceBuilder = jsonBuilder();
sourceBuilder.startObject();
{
@ -535,7 +536,7 @@ public class UpdateRequestTests extends ESTestCase {
}
public void testRoutingExtraction() throws Exception {
GetResult getResult = new GetResult("test", "type", "1", 0, false, null, null);
GetResult getResult = new GetResult("test", "type", "1", UNASSIGNED_SEQ_NO, 0, 0, false, null, null);
IndexRequest indexRequest = new IndexRequest("test", "type", "1");
// There is no routing and parent because the document doesn't exist
@ -545,7 +546,7 @@ public class UpdateRequestTests extends ESTestCase {
assertNull(UpdateHelper.calculateRouting(getResult, indexRequest));
// Doc exists but has no source or fields
getResult = new GetResult("test", "type", "1", 0, true, null, null);
getResult = new GetResult("test", "type", "1", 0, 1, 0, true, null, null);
// There is no routing and parent on either request
assertNull(UpdateHelper.calculateRouting(getResult, indexRequest));
@ -554,7 +555,7 @@ public class UpdateRequestTests extends ESTestCase {
fields.put("_routing", new DocumentField("_routing", Collections.singletonList("routing1")));
// Doc exists and has the parent and routing fields
getResult = new GetResult("test", "type", "1", 0, true, null, fields);
getResult = new GetResult("test", "type", "1", 0, 1, 0, true, null, fields);
// Use the get result parent and routing
assertThat(UpdateHelper.calculateRouting(getResult, indexRequest), equalTo("routing1"));
@ -563,7 +564,7 @@ public class UpdateRequestTests extends ESTestCase {
@SuppressWarnings("deprecated") // VersionType.FORCE is deprecated
public void testCalculateUpdateVersion() throws Exception {
long randomVersion = randomIntBetween(0, 100);
GetResult getResult = new GetResult("test", "type", "1", randomVersion, true, new BytesArray("{}"), null);
GetResult getResult = new GetResult("test", "type", "1", 0, 1, randomVersion, true, new BytesArray("{}"), null);
UpdateRequest request = new UpdateRequest("test", "type1", "1");
long version = UpdateHelper.calculateUpdateVersion(request, getResult);
@ -580,7 +581,7 @@ public class UpdateRequestTests extends ESTestCase {
public void testNoopDetection() throws Exception {
ShardId shardId = new ShardId("test", "", 0);
GetResult getResult = new GetResult("test", "type", "1", 0, true,
GetResult getResult = new GetResult("test", "type", "1", 0, 1, 0, true,
new BytesArray("{\"body\": \"foo\"}"),
null);
@ -611,7 +612,7 @@ public class UpdateRequestTests extends ESTestCase {
public void testUpdateScript() throws Exception {
ShardId shardId = new ShardId("test", "", 0);
GetResult getResult = new GetResult("test", "type", "1", 0, true,
GetResult getResult = new GetResult("test", "type", "1", 0, 1, 0, true,
new BytesArray("{\"body\": \"bar\"}"),
null);

View File

@ -74,11 +74,12 @@ public class UpdateResponseTests extends ESTestCase {
UpdateResponse updateResponse = new UpdateResponse(new ReplicationResponse.ShardInfo(3, 2),
new ShardId("books", "books_uuid", 2), "book", "1", 7, 17, 2, UPDATED);
updateResponse.setGetResult(new GetResult("books", "book", "1", 2, true, source, fields));
updateResponse.setGetResult(new GetResult("books", "book", "1",0, 1, 2, true, source, fields));
String output = Strings.toString(updateResponse);
assertEquals("{\"_index\":\"books\",\"_type\":\"book\",\"_id\":\"1\",\"_version\":2,\"result\":\"updated\"," +
"\"_shards\":{\"total\":3,\"successful\":2,\"failed\":0},\"_seq_no\":7,\"_primary_term\":17,\"get\":{\"found\":true," +
"\"_shards\":{\"total\":3,\"successful\":2,\"failed\":0},\"_seq_no\":7,\"_primary_term\":17,\"get\":{" +
"\"_seq_no\":0,\"_primary_term\":1,\"found\":true," +
"\"_source\":{\"title\":\"Book title\",\"isbn\":\"ABC-123\"},\"fields\":{\"isbn\":[\"ABC-123\"],\"title\":[\"Book " +
"title\"]}}}", output);
}

View File

@ -44,6 +44,7 @@ import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.xcontent.XContentHelper.toXContent;
import static org.elasticsearch.common.xcontent.XContentParserUtils.ensureExpectedToken;
import static org.elasticsearch.index.get.DocumentFieldTests.randomDocumentField;
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
import static org.elasticsearch.test.EqualsHashCodeTestUtils.checkEqualsAndHashCode;
import static org.elasticsearch.test.hamcrest.ElasticsearchAssertions.assertToXContentEquivalent;
@ -72,15 +73,16 @@ public class GetResultTests extends ESTestCase {
public void testToXContent() throws IOException {
{
GetResult getResult = new GetResult("index", "type", "id", 1, true, new BytesArray("{ \"field1\" : " +
GetResult getResult = new GetResult("index", "type", "id", 0, 1, 1, true, new BytesArray("{ \"field1\" : " +
"\"value1\", \"field2\":\"value2\"}"), singletonMap("field1", new DocumentField("field1",
singletonList("value1"))));
String output = Strings.toString(getResult);
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":1,\"found\":true,\"_source\":{ \"field1\" " +
": \"value1\", \"field2\":\"value2\"},\"fields\":{\"field1\":[\"value1\"]}}", output);
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"_version\":1,\"_seq_no\":0,\"_primary_term\":1," +
"\"found\":true,\"_source\":{ \"field1\" : \"value1\", \"field2\":\"value2\"},\"fields\":{\"field1\":[\"value1\"]}}",
output);
}
{
GetResult getResult = new GetResult("index", "type", "id", 1, false, null, null);
GetResult getResult = new GetResult("index", "type", "id", UNASSIGNED_SEQ_NO, 0, 1, false, null, null);
String output = Strings.toString(getResult);
assertEquals("{\"_index\":\"index\",\"_type\":\"type\",\"_id\":\"id\",\"found\":false}", output);
}
@ -92,7 +94,7 @@ public class GetResultTests extends ESTestCase {
GetResult getResult = tuple.v1();
// We don't expect to retrieve the index/type/id of the GetResult because they are not rendered
// by the toXContentEmbedded method.
GetResult expectedGetResult = new GetResult(null, null, null, -1,
GetResult expectedGetResult = new GetResult(null, null, null, tuple.v2().getSeqNo(), tuple.v2().getPrimaryTerm(), -1,
tuple.v2().isExists(), tuple.v2().sourceRef(), tuple.v2().getFields());
boolean humanReadable = randomBoolean();
@ -118,16 +120,16 @@ public class GetResultTests extends ESTestCase {
fields.put("foo", new DocumentField("foo", singletonList("bar")));
fields.put("baz", new DocumentField("baz", Arrays.asList("baz_0", "baz_1")));
GetResult getResult = new GetResult("index", "type", "id", 2, true,
GetResult getResult = new GetResult("index", "type", "id", 0, 1, 2, true,
new BytesArray("{\"foo\":\"bar\",\"baz\":[\"baz_0\",\"baz_1\"]}"), fields);
BytesReference originalBytes = toXContentEmbedded(getResult, XContentType.JSON, false);
assertEquals("{\"found\":true,\"_source\":{\"foo\":\"bar\",\"baz\":[\"baz_0\",\"baz_1\"]}," +
assertEquals("{\"_seq_no\":0,\"_primary_term\":1,\"found\":true,\"_source\":{\"foo\":\"bar\",\"baz\":[\"baz_0\",\"baz_1\"]}," +
"\"fields\":{\"foo\":[\"bar\"],\"baz\":[\"baz_0\",\"baz_1\"]}}", originalBytes.utf8ToString());
}
public void testToXContentEmbeddedNotFound() throws IOException {
GetResult getResult = new GetResult("index", "type", "id", 1, false, null, null);
GetResult getResult = new GetResult("index", "type", "id", UNASSIGNED_SEQ_NO, 0, 1, false, null, null);
BytesReference originalBytes = toXContentEmbedded(getResult, XContentType.JSON, false);
assertEquals("{\"found\":false}", originalBytes.utf8ToString());
@ -149,25 +151,34 @@ public class GetResultTests extends ESTestCase {
}
public static GetResult copyGetResult(GetResult getResult) {
return new GetResult(getResult.getIndex(), getResult.getType(), getResult.getId(), getResult.getVersion(),
getResult.isExists(), getResult.internalSourceRef(), getResult.getFields());
return new GetResult(getResult.getIndex(), getResult.getType(), getResult.getId(),
getResult.getSeqNo(), getResult.getPrimaryTerm(), getResult.getVersion(),
getResult.isExists(), getResult.internalSourceRef(), getResult.getFields());
}
public static GetResult mutateGetResult(GetResult getResult) {
List<Supplier<GetResult>> mutations = new ArrayList<>();
mutations.add(() -> new GetResult(randomUnicodeOfLength(15), getResult.getType(), getResult.getId(), getResult.getVersion(),
mutations.add(() -> new GetResult(randomUnicodeOfLength(15), getResult.getType(), getResult.getId(),
getResult.getSeqNo(), getResult.getPrimaryTerm(), getResult.getVersion(),
getResult.isExists(), getResult.internalSourceRef(), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), randomUnicodeOfLength(15), getResult.getId(), getResult.getVersion(),
getResult.isExists(), getResult.internalSourceRef(), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), getResult.getType(), randomUnicodeOfLength(15), getResult.getVersion(),
getResult.isExists(), getResult.internalSourceRef(), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), getResult.getType(), getResult.getId(), randomNonNegativeLong(),
getResult.isExists(), getResult.internalSourceRef(), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), getResult.getType(), getResult.getId(), getResult.getVersion(),
getResult.isExists() == false, getResult.internalSourceRef(), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), getResult.getType(), getResult.getId(), getResult.getVersion(),
getResult.isExists(), RandomObjects.randomSource(random()), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), getResult.getType(), getResult.getId(), getResult.getVersion(),
mutations.add(() -> new GetResult(getResult.getIndex(), randomUnicodeOfLength(15), getResult.getId(),
getResult.getSeqNo(), getResult.getPrimaryTerm(), getResult.getVersion(),
getResult.isExists(), getResult.internalSourceRef(), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), getResult.getType(), randomUnicodeOfLength(15),
getResult.getSeqNo(), getResult.getPrimaryTerm(), getResult.getVersion(),
getResult.isExists(), getResult.internalSourceRef(), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), getResult.getType(), getResult.getId(),
getResult.getSeqNo(), getResult.getPrimaryTerm(), randomNonNegativeLong(),
getResult.isExists(), getResult.internalSourceRef(), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), getResult.getType(), getResult.getId(),
getResult.isExists() ? UNASSIGNED_SEQ_NO : getResult.getSeqNo(),
getResult.isExists() ? 0 : getResult.getPrimaryTerm(),
getResult.getVersion(), getResult.isExists() == false, getResult.internalSourceRef(), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), getResult.getType(), getResult.getId(),
getResult.getSeqNo(), getResult.getPrimaryTerm(), getResult.getVersion(), getResult.isExists(),
RandomObjects.randomSource(random()), getResult.getFields()));
mutations.add(() -> new GetResult(getResult.getIndex(), getResult.getType(), getResult.getId(),
getResult.getSeqNo(), getResult.getPrimaryTerm(), getResult.getVersion(),
getResult.isExists(), getResult.internalSourceRef(), randomDocumentFields(XContentType.JSON).v1()));
return randomFrom(mutations).get();
}
@ -177,12 +188,16 @@ public class GetResultTests extends ESTestCase {
final String type = randomAlphaOfLengthBetween(3, 10);
final String id = randomAlphaOfLengthBetween(3, 10);
final long version;
final long seqNo;
final long primaryTerm;
final boolean exists;
BytesReference source = null;
Map<String, DocumentField> fields = null;
Map<String, DocumentField> expectedFields = null;
if (frequently()) {
version = randomNonNegativeLong();
seqNo = randomNonNegativeLong();
primaryTerm = randomLongBetween(1, 100);
exists = true;
if (frequently()) {
source = RandomObjects.randomSource(random());
@ -193,11 +208,13 @@ public class GetResultTests extends ESTestCase {
expectedFields = tuple.v2();
}
} else {
seqNo = UNASSIGNED_SEQ_NO;
primaryTerm = 0;
version = -1;
exists = false;
}
GetResult getResult = new GetResult(index, type, id, version, exists, source, fields);
GetResult expectedGetResult = new GetResult(index, type, id, version, exists, source, expectedFields);
GetResult getResult = new GetResult(index, type, id, seqNo, primaryTerm, version, exists, source, fields);
GetResult expectedGetResult = new GetResult(index, type, id, seqNo, primaryTerm, version, exists, source, expectedFields);
return Tuple.tuple(getResult, expectedGetResult);
}

View File

@ -131,7 +131,8 @@ public class GeoShapeQueryBuilderTests extends AbstractQueryTestCase<GeoShapeQue
} catch (IOException ex) {
throw new ElasticsearchException("boom", ex);
}
return new GetResponse(new GetResult(indexedShapeIndex, indexedShapeType, indexedShapeId, 0, true, new BytesArray(json), null));
return new GetResponse(new GetResult(indexedShapeIndex, indexedShapeType, indexedShapeId, 0, 1, 0, true, new BytesArray(json),
null));
}
@After

View File

@ -201,7 +201,8 @@ public class TermsQueryBuilderTests extends AbstractQueryTestCase<TermsQueryBuil
} catch (IOException ex) {
throw new ElasticsearchException("boom", ex);
}
return new GetResponse(new GetResult(getRequest.index(), getRequest.type(), getRequest.id(), 0, true, new BytesArray(json), null));
return new GetResponse(new GetResult(getRequest.index(), getRequest.type(), getRequest.id(), 0, 1, 0, true,
new BytesArray(json), null));
}
public void testNumeric() throws IOException {

View File

@ -32,6 +32,7 @@ import org.elasticsearch.test.rest.FakeRestRequest;
import org.junit.AfterClass;
import static java.util.Collections.emptyMap;
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
import static org.elasticsearch.rest.RestStatus.OK;
import static org.elasticsearch.rest.action.document.RestGetSourceAction.RestGetSourceResponseListener;
import static org.hamcrest.Matchers.equalTo;
@ -51,7 +52,8 @@ public class RestGetSourceActionTests extends ESTestCase {
public void testRestGetSourceAction() throws Exception {
final BytesReference source = new BytesArray("{\"foo\": \"bar\"}");
final GetResponse response = new GetResponse(new GetResult("index1", "_doc", "1", -1, true, source, emptyMap()));
final GetResponse response =
new GetResponse(new GetResult("index1", "_doc", "1", UNASSIGNED_SEQ_NO, 0, -1, true, source, emptyMap()));
final RestResponse restResponse = listener.buildResponse(response);
@ -61,7 +63,8 @@ public class RestGetSourceActionTests extends ESTestCase {
}
public void testRestGetSourceActionWithMissingDocument() {
final GetResponse response = new GetResponse(new GetResult("index1", "_doc", "1", -1, false, null, emptyMap()));
final GetResponse response =
new GetResponse(new GetResult("index1", "_doc", "1", UNASSIGNED_SEQ_NO, 0, -1, false, null, emptyMap()));
final ResourceNotFoundException exception = expectThrows(ResourceNotFoundException.class, () -> listener.buildResponse(response));
@ -69,7 +72,8 @@ public class RestGetSourceActionTests extends ESTestCase {
}
public void testRestGetSourceActionWithMissingDocumentSource() {
final GetResponse response = new GetResponse(new GetResult("index1", "_doc", "1", -1, true, null, emptyMap()));
final GetResponse response =
new GetResponse(new GetResult("index1", "_doc", "1", UNASSIGNED_SEQ_NO, 0, -1, true, null, emptyMap()));
final ResourceNotFoundException exception = expectThrows(ResourceNotFoundException.class, () -> listener.buildResponse(response));

View File

@ -24,6 +24,7 @@ import org.elasticsearch.action.DocWriteRequest;
import org.elasticsearch.action.DocWriteResponse;
import org.elasticsearch.action.bulk.BulkResponse;
import org.elasticsearch.action.delete.DeleteResponse;
import org.elasticsearch.action.get.GetResponse;
import org.elasticsearch.action.index.IndexResponse;
import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.cluster.metadata.IndexMetaData;
@ -311,12 +312,11 @@ public class SimpleVersioningIT extends ESIntegTestCase {
assertThrows(client().prepareDelete("test", "type", "1").setIfMatch(1, 2).execute(), VersionConflictEngineException.class);
client().admin().indices().prepareRefresh().execute().actionGet();
// TODO: Enable once get response returns seqNo
// for (int i = 0; i < 10; i++) {
// final GetResponse response = client().prepareGet("test", "type", "1").get();
// assertThat(response.getSeqNo(), equalTo(1L));
// assertThat(response.getPrimaryTerm(), equalTo(1L));
// }
for (int i = 0; i < 10; i++) {
final GetResponse response = client().prepareGet("test", "type", "1").get();
assertThat(response.getSeqNo(), equalTo(1L));
assertThat(response.getPrimaryTerm(), equalTo(1L));
}
// search with versioning
for (int i = 0; i < 10; i++) {

View File

@ -45,6 +45,7 @@ import java.util.concurrent.CopyOnWriteArrayList;
import java.util.function.Consumer;
import static org.elasticsearch.common.xcontent.XContentFactory.jsonBuilder;
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.notNullValue;
@ -112,7 +113,7 @@ public class NativeUsersStoreTests extends ESTestCase {
SecurityIndexManager.SECURITY_INDEX_NAME,
NativeUsersStore.INDEX_TYPE,
NativeUsersStore.getIdForUser(NativeUsersStore.RESERVED_USER_TYPE, randomAlphaOfLength(12)),
1L,
0, 1, 1L,
true,
BytesReference.bytes(jsonBuilder().map(values)),
Collections.emptyMap());
@ -181,7 +182,7 @@ public class NativeUsersStoreTests extends ESTestCase {
SecurityIndexManager.SECURITY_INDEX_NAME,
NativeUsersStore.INDEX_TYPE,
NativeUsersStore.getIdForUser(NativeUsersStore.USER_DOC_TYPE, username),
1L,
UNASSIGNED_SEQ_NO, 0, 1L,
false,
null,
Collections.emptyMap());
@ -223,7 +224,7 @@ public class NativeUsersStoreTests extends ESTestCase {
SecurityIndexManager.SECURITY_INDEX_NAME,
NativeUsersStore.INDEX_TYPE,
NativeUsersStore.getIdForUser(NativeUsersStore.USER_DOC_TYPE, username),
1L,
0, 1, 1L,
true,
source,
Collections.emptyMap());

View File

@ -56,6 +56,7 @@ import java.util.function.Consumer;
import static java.util.Collections.emptyMap;
import static org.elasticsearch.common.util.set.Sets.newHashSet;
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
import static org.hamcrest.Matchers.arrayContaining;
import static org.hamcrest.Matchers.contains;
import static org.hamcrest.Matchers.containsInAnyOrder;
@ -129,7 +130,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
final String docSource = Strings.toString(sourcePrivilege);
listener.get().onResponse(new GetResponse(
new GetResult(request.index(), request.type(), request.id(), 1L, true, new BytesArray(docSource), emptyMap())
new GetResult(request.index(), request.type(), request.id(), 0, 1, 1L, true, new BytesArray(docSource), emptyMap())
));
final ApplicationPrivilegeDescriptor getPrivilege = future.get(1, TimeUnit.SECONDS);
assertThat(getPrivilege, equalTo(sourcePrivilege));
@ -146,7 +147,7 @@ public class NativePrivilegeStoreTests extends ESTestCase {
assertThat(request.id(), equalTo("application-privilege_myapp:admin"));
listener.get().onResponse(new GetResponse(
new GetResult(request.index(), request.type(), request.id(), -1, false, null, emptyMap())
new GetResult(request.index(), request.type(), request.id(), UNASSIGNED_SEQ_NO, 0, -1, false, null, emptyMap())
));
final ApplicationPrivilegeDescriptor getPrivilege = future.get(1, TimeUnit.SECONDS);
assertThat(getPrivilege, Matchers.nullValue());

View File

@ -24,6 +24,7 @@ import org.elasticsearch.common.util.concurrent.EsRejectedExecutionException;
import org.elasticsearch.common.util.concurrent.ThreadContext;
import org.elasticsearch.common.xcontent.DeprecationHandler;
import org.elasticsearch.common.xcontent.NamedXContentRegistry;
import org.elasticsearch.common.xcontent.ObjectPath;
import org.elasticsearch.common.xcontent.XContentFactory;
import org.elasticsearch.common.xcontent.XContentParser;
import org.elasticsearch.common.xcontent.XContentType;
@ -53,7 +54,6 @@ import org.elasticsearch.xpack.core.watcher.execution.Wid;
import org.elasticsearch.xpack.core.watcher.history.WatchRecord;
import org.elasticsearch.xpack.core.watcher.input.ExecutableInput;
import org.elasticsearch.xpack.core.watcher.input.Input;
import org.elasticsearch.common.xcontent.ObjectPath;
import org.elasticsearch.xpack.core.watcher.transform.ExecutableTransform;
import org.elasticsearch.xpack.core.watcher.transform.Transform;
import org.elasticsearch.xpack.core.watcher.trigger.TriggerEvent;
@ -88,6 +88,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
import static java.util.Arrays.asList;
import static java.util.Collections.singletonMap;
import static org.elasticsearch.common.unit.TimeValue.timeValueSeconds;
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.greaterThan;
import static org.hamcrest.Matchers.hasSize;
@ -1148,7 +1149,8 @@ public class ExecutionServiceTests extends ESTestCase {
if (request.id().equals(id)) {
listener.onResponse(response);
} else {
GetResult notFoundResult = new GetResult(request.index(), request.type(), request.id(), -1, false, null, null);
GetResult notFoundResult =
new GetResult(request.index(), request.type(), request.id(), UNASSIGNED_SEQ_NO, 0, -1, false, null, null);
listener.onResponse(new GetResponse(notFoundResult));
}
return null;
@ -1162,7 +1164,8 @@ public class ExecutionServiceTests extends ESTestCase {
if (request.id().equals(id)) {
listener.onFailure(e);
} else {
GetResult notFoundResult = new GetResult(request.index(), request.type(), request.id(), -1, false, null, null);
GetResult notFoundResult =
new GetResult(request.index(), request.type(), request.id(), UNASSIGNED_SEQ_NO, 0, -1, false, null, null);
listener.onResponse(new GetResponse(notFoundResult));
}
return null;

View File

@ -38,6 +38,7 @@ import java.time.Clock;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import static org.elasticsearch.index.seqno.SequenceNumbers.UNASSIGNED_SEQ_NO;
import static org.hamcrest.Matchers.is;
import static org.mockito.Matchers.anyObject;
import static org.mockito.Matchers.eq;
@ -67,7 +68,7 @@ public class TransportAckWatchActionTests extends ESTestCase {
String watchId = "my_watch_id";
doAnswer(invocation -> {
ActionListener<GetResponse> listener = (ActionListener<GetResponse>) invocation.getArguments()[1];
listener.onResponse(new GetResponse(new GetResult(Watch.INDEX, Watch.DOC_TYPE, watchId, -1, false,
listener.onResponse(new GetResponse(new GetResult(Watch.INDEX, Watch.DOC_TYPE, watchId, UNASSIGNED_SEQ_NO, 0, -1, false,
BytesArray.EMPTY, Collections.emptyMap())));
return null;
}).when(client).get(anyObject(), anyObject());