You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by tf...@apache.org on 2019/01/25 21:41:59 UTC
[lucene-solr] branch branch_8x updated: SOLR-12373: Let
DocBasedVersionConstraintsProcessor define fields to use in tombstones
This is an automated email from the ASF dual-hosted git repository.
tflobbe pushed a commit to branch branch_8x
in repository https://gitbox.apache.org/repos/asf/lucene-solr.git
The following commit(s) were added to refs/heads/branch_8x by this push:
new 45bf00b SOLR-12373: Let DocBasedVersionConstraintsProcessor define fields to use in tombstones
45bf00b is described below
commit 45bf00bf05ad4e0f92fddd0e11dd1f8871dc5751
Author: Tomas Fernandez Lobbe <tf...@apache.org>
AuthorDate: Fri Jan 25 13:38:18 2019 -0800
SOLR-12373: Let DocBasedVersionConstraintsProcessor define fields to use in tombstones
A new config option, "tombstoneConfig" allows the DocBasedVersionConstraintsProcessor
to add extra fields to the tombstone generated when a document is deleted. This can
be useful when the schema has required fields.
---
solr/CHANGES.txt | 5 +
.../DocBasedVersionConstraintsProcessor.java | 71 +++++++---
...DocBasedVersionConstraintsProcessorFactory.java | 52 +++++++-
.../conf/solrconfig-externalversionconstraint.xml | 19 +++
.../TestDocBasedVersionConstraints.java | 145 ++++++++++++++++++++-
5 files changed, 271 insertions(+), 21 deletions(-)
diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt
index 811f44f..723bf75 100644
--- a/solr/CHANGES.txt
+++ b/solr/CHANGES.txt
@@ -230,6 +230,11 @@ New Features
* SOLR-12770: Make it possible to configure a host whitelist for distributed search
(Christine Poerschke, janhoy, Erick Erickson, Tomás Fernández Löbbe)
+* SOLR-12373: Add a "tombstoneConfig" option to DocBasedVersionConstraintsProcessor that allows
+ users to configure which fields/values to add to tombstone documents. This can be useful to
+ make sure tombstone documents include fields that are marked as required in the schema
+ (Tomás Fernández Löbbe)
+
Bug Fixes
----------------------
diff --git a/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessor.java b/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessor.java
index fa805d7..b7dcb30 100644
--- a/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessor.java
+++ b/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessor.java
@@ -17,12 +17,16 @@
package org.apache.solr.update.processor;
+import static org.apache.solr.common.SolrException.ErrorCode.BAD_REQUEST;
+import static org.apache.solr.common.SolrException.ErrorCode.CONFLICT;
+import static org.apache.solr.common.SolrException.ErrorCode.SERVER_ERROR;
+import static org.apache.solr.update.processor.DistributingUpdateProcessorFactory.DISTRIB_UPDATE_PARAM;
+
import java.io.IOException;
import java.lang.invoke.MethodHandles;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
-
import org.apache.lucene.index.LeafReaderContext;
import org.apache.lucene.queries.function.FunctionValues;
import org.apache.lucene.queries.function.ValueSource;
@@ -32,6 +36,7 @@ import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.params.CommonParams;
import org.apache.solr.common.params.SolrParams;
+import org.apache.solr.common.util.NamedList;
import org.apache.solr.core.SolrCore;
import org.apache.solr.handler.component.RealTimeGetComponent;
import org.apache.solr.request.SolrQueryRequest;
@@ -46,11 +51,6 @@ import org.apache.solr.util.RefCounted;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static org.apache.solr.common.SolrException.ErrorCode.BAD_REQUEST;
-import static org.apache.solr.common.SolrException.ErrorCode.CONFLICT;
-import static org.apache.solr.common.SolrException.ErrorCode.SERVER_ERROR;
-import static org.apache.solr.update.processor.DistributingUpdateProcessorFactory.DISTRIB_UPDATE_PARAM;
-
public class DocBasedVersionConstraintsProcessor extends UpdateRequestProcessor {
private static final String[] EMPTY_STR_ARR = new String[0];
private static final Logger log = LoggerFactory.getLogger(MethodHandles.lookup().lookupClass());
@@ -62,18 +62,41 @@ public class DocBasedVersionConstraintsProcessor extends UpdateRequestProcessor
private final boolean supportMissingVersionOnOldDocs;
private final String[] deleteVersionParamNames;
private final SolrCore core;
+ private final NamedList<Object> tombstoneConfig;
private final DistributedUpdateProcessor distribProc; // the distributed update processor following us
private final DistributedUpdateProcessor.DistribPhase phase;
private final boolean useFieldCache;
private long oldSolrVersion; // current _version_ of the doc in the index/update log
+
+ /**
+ * @deprecated Use {@link #DocBasedVersionConstraintsProcessor(List, boolean, List, boolean, boolean, NamedList, SolrQueryRequest, UpdateRequestProcessor)}
+ */
+ @Deprecated
+ public DocBasedVersionConstraintsProcessor(List<String> versionFields,
+ boolean ignoreOldUpdates,
+ List<String> deleteVersionParamNames,
+ boolean supportMissingVersionOnOldDocs,
+ boolean useFieldCache,
+ SolrQueryRequest req,
+ UpdateRequestProcessor next ) {
+ this(versionFields,
+ ignoreOldUpdates,
+ deleteVersionParamNames,
+ supportMissingVersionOnOldDocs,
+ useFieldCache,
+ null,
+ req,
+ next);
+ }
public DocBasedVersionConstraintsProcessor(List<String> versionFields,
boolean ignoreOldUpdates,
List<String> deleteVersionParamNames,
boolean supportMissingVersionOnOldDocs,
boolean useFieldCache,
+ NamedList<Object> tombstoneConfig,
SolrQueryRequest req,
UpdateRequestProcessor next ) {
super(next);
@@ -93,6 +116,7 @@ public class DocBasedVersionConstraintsProcessor extends UpdateRequestProcessor
this.distribProc = getDistributedUpdateProcessor(next);
this.phase = DistributedUpdateProcessor.DistribPhase.parseParam(req.getParams().get(DISTRIB_UPDATE_PARAM));
+ this.tombstoneConfig = tombstoneConfig;
}
private static DistributedUpdateProcessor getDistributedUpdateProcessor(UpdateRequestProcessor next) {
@@ -429,10 +453,7 @@ public class DocBasedVersionConstraintsProcessor extends UpdateRequestProcessor
if (isNotLeader(cmd)) {
// transform delete to add earlier rather than later
- SolrInputDocument newDoc = new SolrInputDocument();
- newDoc.setField(core.getLatestSchema().getUniqueKeyField().getName(),
- cmd.getId());
- setDeleteParamValues(newDoc, deleteParamValues);
+ SolrInputDocument newDoc = createTombstoneDocument(core.getLatestSchema(), cmd.getId(), versionFieldNames, deleteParamValues, this.tombstoneConfig);
AddUpdateCommand newCmd = new AddUpdateCommand(cmd.getReq());
newCmd.solrDoc = newDoc;
@@ -458,10 +479,7 @@ public class DocBasedVersionConstraintsProcessor extends UpdateRequestProcessor
// drop the delete, and instead propagate an AddDoc that
// replaces the doc with a new "empty" one that records the deleted version
- SolrInputDocument newDoc = new SolrInputDocument();
- newDoc.setField(core.getLatestSchema().getUniqueKeyField().getName(),
- cmd.getId());
- setDeleteParamValues(newDoc, deleteParamValues);
+ SolrInputDocument newDoc = createTombstoneDocument(core.getLatestSchema(), cmd.getId(), versionFieldNames, deleteParamValues, this.tombstoneConfig);
AddUpdateCommand newCmd = new AddUpdateCommand(cmd.getReq());
newCmd.solrDoc = newDoc;
@@ -479,6 +497,29 @@ public class DocBasedVersionConstraintsProcessor extends UpdateRequestProcessor
}
}
+
+ /**
+ * Creates a tombstone document, that will be used to update a document that's being deleted by ID. The returned document will contain:
+ * <ul>
+ * <li>uniqueKey</li>
+ * <li>versions (All the fields configured as in the {@code versionField} parameter)</li>
+ * <li>All the fields set in the {@code tombstoneConfig} parameter</li>
+ * </ul>
+ *
+ * Note that if the schema contains required fields (other than version fields or uniqueKey), they should be populated by the {@code tombstoneConfig},
+ * otherwise this tombstone will fail when indexing (and consequently the delete will fail). Alternatively, required fields must be populated by some
+ * other means (like {@code DocBasedVersionConstraintsProcessorFactory} or similar)
+ */
+ protected SolrInputDocument createTombstoneDocument(IndexSchema schema, String id, String[] versionFieldNames, String[] deleteParamValues, NamedList<Object> tombstoneConfig) {
+ final SolrInputDocument newDoc = new SolrInputDocument();
+
+ if (tombstoneConfig != null) {
+ tombstoneConfig.forEach((k,v) -> newDoc.addField(k, v));
+ }
+ newDoc.setField(schema.getUniqueKeyField().getName(), id);
+ setDeleteParamValues(newDoc, versionFieldNames, deleteParamValues);
+ return newDoc;
+ }
private String[] getDeleteParamValuesFromRequest(DeleteUpdateCommand cmd) {
SolrParams params = cmd.getReq().getParams();
@@ -503,7 +544,7 @@ public class DocBasedVersionConstraintsProcessor extends UpdateRequestProcessor
}
}
- private void setDeleteParamValues(SolrInputDocument doc, String[] values) {
+ private static void setDeleteParamValues(SolrInputDocument doc, String[] versionFieldNames, String[] values) {
for (int i = 0; i < values.length; i++) {
String versionFieldName = versionFieldNames[i];
String value = values[i];
diff --git a/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessorFactory.java b/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessorFactory.java
index a8ee9b5..b2200d3 100644
--- a/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessorFactory.java
+++ b/solr/core/src/java/org/apache/solr/update/processor/DocBasedVersionConstraintsProcessorFactory.java
@@ -16,23 +16,25 @@
*/
package org.apache.solr.update.processor;
+import static org.apache.solr.common.SolrException.ErrorCode.SERVER_ERROR;
+
import java.lang.invoke.MethodHandles;
import java.util.Collections;
import java.util.List;
-
+import java.util.Set;
+import java.util.stream.Collectors;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.StrUtils;
import org.apache.solr.core.SolrCore;
import org.apache.solr.request.SolrQueryRequest;
import org.apache.solr.response.SolrQueryResponse;
+import org.apache.solr.schema.IndexSchema;
import org.apache.solr.schema.SchemaField;
import org.apache.solr.util.plugin.SolrCoreAware;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static org.apache.solr.common.SolrException.ErrorCode.SERVER_ERROR;
-
/**
* <p>
* This Factory generates an UpdateProcessor that helps to enforce Version
@@ -85,6 +87,9 @@ import static org.apache.solr.common.SolrException.ErrorCode.SERVER_ERROR;
* <code>false</code>, but if set to <code>true</code> allows any documents written *before*
* this feature is enabled and which are missing the versionField to be overwritten.
* </li>
+ * <li><code>tombstoneConfig</code> - a list of field names to values to add to the
+ * created tombstone document. In general is not a good idea to populate tombsone documents
+ * with anything other than the minimum required fields so that it doean't match queries</li>
* </ul>
* @since 4.6.0
*/
@@ -96,7 +101,9 @@ public class DocBasedVersionConstraintsProcessorFactory extends UpdateRequestPro
private List<String> deleteVersionParamNames = Collections.emptyList();
private boolean useFieldCache;
private boolean supportMissingVersionOnOldDocs = false;
+ private NamedList<Object> tombstoneConfig;
+ @SuppressWarnings("unchecked")
@Override
public void init( NamedList args ) {
@@ -145,6 +152,15 @@ public class DocBasedVersionConstraintsProcessorFactory extends UpdateRequestPro
}
supportMissingVersionOnOldDocs = ((Boolean)tmp).booleanValue();
}
+
+ tmp = args.remove("tombstoneConfig");
+ if (null != tmp) {
+ if (! (tmp instanceof NamedList) ) {
+ throw new SolrException(SERVER_ERROR,
+ "'tombstoneConfig' must be configured as a <lst>.");
+ }
+ tombstoneConfig = (NamedList<Object>)tmp;
+ }
super.init(args);
}
@@ -158,6 +174,7 @@ public class DocBasedVersionConstraintsProcessorFactory extends UpdateRequestPro
deleteVersionParamNames,
supportMissingVersionOnOldDocs,
useFieldCache,
+ tombstoneConfig,
req, next);
}
@@ -190,7 +207,34 @@ public class DocBasedVersionConstraintsProcessorFactory extends UpdateRequestPro
}
}
}
+
+ canCreateTombstoneDocument(core.getLatestSchema());
+ }
+
+ /**
+ * Validates that the schema would allow tombstones to be created by DocBasedVersionConstraintsProcessor by
+ * checking if the required fields are of known types
+ */
+ protected boolean canCreateTombstoneDocument(IndexSchema schema) {
+ Set<String> requiredFieldNames = schema.getRequiredFields().stream()
+ .filter(field -> field.getDefaultValue() == null)
+ .map(field -> field.getName())
+ .collect(Collectors.toSet());
+ if (tombstoneConfig != null) {
+ tombstoneConfig.forEach((k,v) -> requiredFieldNames.remove(k));
+ }
+ requiredFieldNames.remove(schema.getUniqueKeyField().getName());
+ if (versionFields != null) {
+ versionFields.forEach(field -> requiredFieldNames.remove(field));
+ }
+ if (!requiredFieldNames.isEmpty()) {
+ log.warn("The schema \"{}\" has required fields that aren't added in the tombstone."
+ + " This can cause deletes to fail if those aren't being added in some other way. Required Fields={}",
+ schema.getSchemaName(),
+ requiredFieldNames);
+ return false;
+ }
+ return true;
}
-
}
diff --git a/solr/core/src/test-files/solr/collection1/conf/solrconfig-externalversionconstraint.xml b/solr/core/src/test-files/solr/collection1/conf/solrconfig-externalversionconstraint.xml
index cd18d1e..15a188a 100644
--- a/solr/core/src/test-files/solr/collection1/conf/solrconfig-externalversionconstraint.xml
+++ b/solr/core/src/test-files/solr/collection1/conf/solrconfig-externalversionconstraint.xml
@@ -151,5 +151,24 @@
<processor class="solr.RunUpdateProcessorFactory" />
</updateRequestProcessorChain>
+
+ <updateRequestProcessorChain name="tombstone-config">
+ <!-- process the external version constraint, ignoring any updates that
+ don't satisfy the constraint -->
+ <processor class="solr.DocBasedVersionConstraintsProcessorFactory">
+ <str name="versionField">my_version_l</str>
+ <str name="deleteVersionParam">del_version</str>
+ <lst name="tombstoneConfig">
+ <bool name="foo_b">true</bool>
+ <int name="foo_i">1</int>
+ <long name="foo_l">1</long>
+ <float name="foo_f">1.5</float>
+ <str name="foo_s">bar</str>
+ <str name="foo_ss">bar1</str>
+ <str name="foo_ss">bar2</str>
+ </lst>
+ </processor>
+ <processor class="solr.RunUpdateProcessorFactory" />
+ </updateRequestProcessorChain>
</config>
diff --git a/solr/core/src/test/org/apache/solr/update/TestDocBasedVersionConstraints.java b/solr/core/src/test/org/apache/solr/update/processor/TestDocBasedVersionConstraints.java
similarity index 78%
rename from solr/core/src/test/org/apache/solr/update/TestDocBasedVersionConstraints.java
rename to solr/core/src/test/org/apache/solr/update/processor/TestDocBasedVersionConstraints.java
index 8580f52..917afad 100644
--- a/solr/core/src/test/org/apache/solr/update/TestDocBasedVersionConstraints.java
+++ b/solr/core/src/test/org/apache/solr/update/processor/TestDocBasedVersionConstraints.java
@@ -14,18 +14,28 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package org.apache.solr.update;
+package org.apache.solr.update.processor;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.CoreMatchers.not;
+import static org.hamcrest.CoreMatchers.nullValue;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.hasItem;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
-
import org.apache.lucene.util.TestUtil;
import org.apache.solr.SolrTestCaseJ4;
import org.apache.solr.common.SolrException;
+import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.util.ExecutorUtil;
+import org.apache.solr.common.util.NamedList;
+import org.apache.solr.schema.IndexSchema;
+import org.apache.solr.schema.SchemaField;
+import org.apache.solr.update.processor.DocBasedVersionConstraintsProcessorFactory;
import org.apache.solr.util.DefaultSolrThreadFactory;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -353,11 +363,13 @@ public class TestDocBasedVersionConstraints extends SolrTestCaseJ4 {
}
// And just verify if we pass version 1, we still error if version 2 isn't found.
try {
+ ignoreException("Delete by ID must specify doc version param");
deleteAndGetVersion("aaa", params("del_version", "1001",
"update.chain","external-version-failhard-multiple"));
fail("no 400");
} catch (SolrException ex) {
assertEquals(400, ex.code());
+ unIgnoreException("Delete by ID must specify doc version param");
}
//Verify we are still unchanged
assertU(commit());
@@ -497,12 +509,14 @@ public class TestDocBasedVersionConstraints extends SolrTestCaseJ4 {
updateJ(json("[{\"id\": \"a\", \"name\": \"a1\", \"my_version_l\": " + version + "}]"),
params("update.chain", "external-version-constraint"));
try {
+ ignoreException("Doc exists in index, but has null versionField: my_version_l");
updateJ(json("[{\"id\": \"b\", \"name\": \"b1\", \"my_version_l\": " + version + "}]"),
params("update.chain", "external-version-constraint"));
fail("Update to id=b should have failed because existing doc is missing version field");
} catch (final SolrException ex) {
// expected
assertEquals("Doc exists in index, but has null versionField: my_version_l", ex.getMessage());
+ unIgnoreException("Doc exists in index, but has null versionField: my_version_l");
}
assertU(commit());
assertJQ(req("q","*:*"), "/response/numFound==2");
@@ -523,6 +537,133 @@ public class TestDocBasedVersionConstraints extends SolrTestCaseJ4 {
assertJQ(req("qt","/get", "id", "b", "fl", "id,my_version_l"), "=={'doc':{'id':'b', 'my_version_l':1}}");
}
+ public void testTombstoneConfig() throws Exception {
+ assertJQ(req("q","*:*"),"/response/numFound==0");
+ updateWithChain("tombstone-config",
+ "id", "b!doc1",
+ "my_version_l", "1");
+ assertU(commit());
+ assertJQ(req("q","*:*"),"/response/numFound==1");
+ assertJQ(req("q","foo_b:true"),"/response/numFound==0");
+ assertJQ(req("q","foo_i:1"),"/response/numFound==0");
+ assertJQ(req("q","foo_l:1"),"/response/numFound==0");
+ assertJQ(req("q","foo_f:1.5"),"/response/numFound==0");
+ assertJQ(req("q","foo_s:bar"),"/response/numFound==0");
+ assertJQ(req("q","foo_ss:bar1"),"/response/numFound==0");
+ assertJQ(req("q","foo_ss:bar2"),"/response/numFound==0");
+
+ deleteAndGetVersion("b!doc1",
+ params("del_version", "2", "update.chain",
+ "tombstone-config"));
+ assertU(commit());
+
+ assertJQ(req("q","foo_b:true"),"/response/numFound==1");
+ assertJQ(req("q","foo_i:1"),"/response/numFound==1");
+ assertJQ(req("q","foo_l:1"),"/response/numFound==1");
+ assertJQ(req("q","foo_f:1.5"),"/response/numFound==1");
+ assertJQ(req("q","foo_s:bar"),"/response/numFound==1");
+ assertJQ(req("q","foo_ss:bar1"),"/response/numFound==1");
+ assertJQ(req("q","foo_ss:bar2"),"/response/numFound==1");
+ }
+
+ public void testCanCreateTombstonesBasic() {
+ DocBasedVersionConstraintsProcessorFactory factory = new DocBasedVersionConstraintsProcessorFactory();
+ NamedList<Object> config = new NamedList<>();
+ config.add("versionField", "_version_");
+ factory.init(config);
+ IndexSchema schema = h.getCore().getLatestSchema();
+ assertThat(factory.canCreateTombstoneDocument(schema), is(true));
+ }
+
+ public void testCanCreateTombstonesMissingRequiredField() {
+ DocBasedVersionConstraintsProcessorFactory factory = new DocBasedVersionConstraintsProcessorFactory();
+ NamedList<Object> config = new NamedList<>();
+ config.add("versionField", "_version_");
+ factory.init(config);
+ IndexSchema schema = h.getCore().getLatestSchema();
+ SchemaField sf = schema.getField("sku1");
+ assertThat(sf, is(not(nullValue())));
+ assertThat(schema.getRequiredFields(), not(hasItem(sf)));
+ try {
+ schema.getRequiredFields().add(sf);
+ assertThat(factory.canCreateTombstoneDocument(schema), is(false));
+ } finally {
+ schema.getRequiredFields().remove(sf);
+ }
+ }
+
+ public void testCanCreateTombstonesRequiredFieldWithDefault() {
+ DocBasedVersionConstraintsProcessorFactory factory = new DocBasedVersionConstraintsProcessorFactory();
+ NamedList<Object> config = new NamedList<>();
+ config.add("versionField", "_version_");
+ factory.init(config);
+ IndexSchema schema = h.getCore().getLatestSchema();
+ SchemaField sf = schema.getField("sku1");
+ SchemaField sf2 = new SchemaField("sku1_with_default", sf.getType(), sf.getProperties(), "foo");
+ try {
+ schema.getRequiredFields().add(sf2);
+ assertThat(factory.canCreateTombstoneDocument(schema), is(true));
+ } finally {
+ schema.getRequiredFields().remove(sf2);
+ }
+ }
+
+ public void testCanCreateTombstonesRequiredFieldInTombstoneConfig() {
+ DocBasedVersionConstraintsProcessorFactory factory = new DocBasedVersionConstraintsProcessorFactory();
+ NamedList<Object> config = new NamedList<>();
+ config.add("versionField", "_version_");
+ NamedList<Object> tombstoneConfig = new NamedList<>();
+ config.add("tombstoneConfig", tombstoneConfig);
+ tombstoneConfig.add("sku1", "foo");
+ factory.init(config);
+ IndexSchema schema = h.getCore().getLatestSchema();
+ SchemaField sf = schema.getField("sku1");
+ assertThat(sf, is(not(nullValue())));
+ assertThat(schema.getRequiredFields(), not(hasItem(sf)));
+ try {
+ schema.getRequiredFields().add(sf);
+ assertThat(factory.canCreateTombstoneDocument(schema), is(true));
+ } finally {
+ schema.getRequiredFields().remove(sf);
+ }
+ }
+
+ public void testCanCreateTombstonesVersionFieldRequired() {
+ DocBasedVersionConstraintsProcessorFactory factory = new DocBasedVersionConstraintsProcessorFactory();
+ NamedList<Object> config = new NamedList<>();
+ config.add("versionField", "_version_");
+ factory.init(config);
+ IndexSchema schema = h.getCore().getLatestSchema();
+ SchemaField versionField = schema.getField("_version_");
+ assertThat(versionField, is(not(nullValue())));
+ assertThat(schema.getRequiredFields(), not(hasItem(versionField)));
+ try {
+ schema.getRequiredFields().add(versionField);
+ assertThat(factory.canCreateTombstoneDocument(schema), is(true));
+ } finally {
+ schema.getRequiredFields().remove(versionField);
+ }
+ }
+
+ public void testCanCreateTombstonesUniqueKeyFieldRequired() {
+ DocBasedVersionConstraintsProcessorFactory factory = new DocBasedVersionConstraintsProcessorFactory();
+ NamedList<Object> config = new NamedList<>();
+ config.add("versionField", "_version_");
+ factory.init(config);
+ IndexSchema schema = h.getCore().getLatestSchema();
+ SchemaField uniqueKeyField = schema.getField("id");
+ assertThat(uniqueKeyField, is(not(nullValue())));
+ assertThat(uniqueKeyField, equalTo(schema.getUniqueKeyField()));
+ assertThat(schema.getRequiredFields(), hasItem(schema.getUniqueKeyField()));
+ assertThat(factory.canCreateTombstoneDocument(schema), is(true));
+ }
+
+ private void updateWithChain(String chain, String...fields) throws Exception {
+ assert fields.length % 2 == 0;
+ SolrInputDocument doc = new SolrInputDocument(fields);
+ updateJ(jsonAdd(doc), params("update.chain", chain));
+ }
+
private Callable<Object> delayedAdd(final String... fields) {
return Executors.callable(() -> {
// log.info("ADDING DOC: " + adoc(fields));