You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@lucene.apache.org by ho...@apache.org on 2016/03/12 01:27:10 UTC
[29/50] [abbrv] lucene-solr git commit: SOLR-445: refactored KnownErr
-> ToleratedUpdateError in solr-common
SOLR-445: refactored KnownErr -> ToleratedUpdateError in solr-common
Also added some nehnacments to that class, and replaced the hack in CloudSolrClient with usage of this class
Project: http://git-wip-us.apache.org/repos/asf/lucene-solr/repo
Commit: http://git-wip-us.apache.org/repos/asf/lucene-solr/commit/c37d5a86
Tree: http://git-wip-us.apache.org/repos/asf/lucene-solr/tree/c37d5a86
Diff: http://git-wip-us.apache.org/repos/asf/lucene-solr/diff/c37d5a86
Branch: refs/heads/jira/SOLR-445
Commit: c37d5a8618c1af41a5cda45463ab1288ea73b99b
Parents: 5b405b6
Author: Chris Hostetter <ho...@apache.org>
Authored: Thu Mar 10 11:22:08 2016 -0700
Committer: Chris Hostetter <ho...@apache.org>
Committed: Thu Mar 10 11:22:08 2016 -0700
----------------------------------------------------------------------
.../processor/TolerantUpdateProcessor.java | 124 +++------------
.../cloud/TestTolerantUpdateProcessorCloud.java | 25 ++--
.../processor/TolerantUpdateProcessorTest.java | 37 +----
.../solr/client/solrj/impl/CloudSolrClient.java | 8 +-
.../solr/common/ToleratedUpdateError.java | 150 +++++++++++++++++++
.../solr/common/TestToleratedUpdateError.java | 89 +++++++++++
6 files changed, 281 insertions(+), 152 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c37d5a86/solr/core/src/java/org/apache/solr/update/processor/TolerantUpdateProcessor.java
----------------------------------------------------------------------
diff --git a/solr/core/src/java/org/apache/solr/update/processor/TolerantUpdateProcessor.java b/solr/core/src/java/org/apache/solr/update/processor/TolerantUpdateProcessor.java
index dc07082..30e5f80 100644
--- a/solr/core/src/java/org/apache/solr/update/processor/TolerantUpdateProcessor.java
+++ b/solr/core/src/java/org/apache/solr/update/processor/TolerantUpdateProcessor.java
@@ -29,6 +29,8 @@ import org.apache.lucene.util.CharsRefBuilder;
import org.apache.solr.cloud.ZkController;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.common.ToleratedUpdateError;
+import org.apache.solr.common.ToleratedUpdateError.CmdType;
import org.apache.solr.common.cloud.DocCollection;
import org.apache.solr.common.cloud.Slice;
import org.apache.solr.common.params.ShardParams;
@@ -53,7 +55,7 @@ import org.slf4j.LoggerFactory;
* will receive a 200 response, but gets a list of errors (keyed by
* unique key) unless <code>maxErrors</code> is reached.
* If <code>maxErrors</code> occur, the first exception caught will be re-thrown,
- * Solr will respond with 5XX or 4XX (depending on the exception) and
+ * Solr will respond with 5XX or 4XX (depending on the underlying exceptions) and
* it won't finish processing the batch. This means that the last docs
* in the batch may not be added in this case even if they are valid.
* </p>
@@ -94,7 +96,7 @@ public class TolerantUpdateProcessor extends UpdateRequestProcessor {
* Known errors that occurred in this batch, in order encountered (may not be the same as the
* order the commands were originally executed in due to the async distributed updates).
*/
- private final List<KnownErr> knownErrors = new ArrayList<KnownErr>();
+ private final List<ToleratedUpdateError> knownErrors = new ArrayList<ToleratedUpdateError>();
// Kludge: Because deleteByQuery updates are forwarded to every leader, we can get identical
// errors reported by every leader for the same underlying problem.
@@ -109,13 +111,13 @@ public class TolerantUpdateProcessor extends UpdateRequestProcessor {
// dbq: foo:bar
//
// ...but i can't figure out a way to accurately identify & return duplicate
- // KnownErrs from duplicate identical underlying requests w/o erroneously returning identical
- // KnownErrs for the *same* underlying request but from diff shards.
+ // ToleratedUpdateErrors from duplicate identical underlying requests w/o erroneously returning identical
+ // ToleratedUpdateErrors for the *same* underlying request but from diff shards.
//
// So as a kludge, we keep track of them for deduping against identical remote failures
//
// :nocommit: probably need to use this for "commit" as well?
- private Set<KnownErr> knownDBQErrors = new HashSet<>();
+ private Set<ToleratedUpdateError> knownDBQErrors = new HashSet<>();
private final FirstErrTracker firstErrTracker = new FirstErrTracker();
private final DistribPhase distribPhase;
@@ -153,9 +155,10 @@ public class TolerantUpdateProcessor extends UpdateRequestProcessor {
if (isLeader || distribPhase.equals(DistribPhase.NONE)) {
// nocommit: should we skip if condition and always do this? see comment in else...
- knownErrors.add(new KnownErr(CmdType.ADD,
- getPrintableId(id, cmd.getReq().getSchema().getUniqueKeyField()),
- t.getMessage()));
+ knownErrors.add(new ToleratedUpdateError
+ (CmdType.ADD,
+ getPrintableId(id, cmd.getReq().getSchema().getUniqueKeyField()),
+ t.getMessage()));
if (knownErrors.size() > maxErrors) {
firstErrTracker.throwFirst();
}
@@ -185,9 +188,9 @@ public class TolerantUpdateProcessor extends UpdateRequestProcessor {
// nocommit: do we need isLeader type logic like processAdd ? does processAdd even need it?
- KnownErr err = new KnownErr(cmd.isDeleteById() ? CmdType.DELID : CmdType.DELQ,
- cmd.isDeleteById() ? cmd.id : cmd.query,
- t.getMessage());
+ ToleratedUpdateError err = new ToleratedUpdateError(cmd.isDeleteById() ? CmdType.DELID : CmdType.DELQ,
+ cmd.isDeleteById() ? cmd.id : cmd.query,
+ t.getMessage());
knownErrors.add(err);
// NOTE: we're not using this to dedup before adding to knownErrors.
@@ -241,8 +244,9 @@ public class TolerantUpdateProcessor extends UpdateRequestProcessor {
}
for (int i = 0; i < remoteErrMetadata.size(); i++) {
- KnownErr err = KnownErr.parseMetadataIfKnownErr(remoteErrMetadata.getName(i),
- remoteErrMetadata.getVal(i));
+ ToleratedUpdateError err =
+ ToleratedUpdateError.parseMetadataIfToleratedUpdateError(remoteErrMetadata.getName(i),
+ remoteErrMetadata.getVal(i));
if (null == err) {
// some metadata unrelated to this update processor
continue;
@@ -262,7 +266,7 @@ public class TolerantUpdateProcessor extends UpdateRequestProcessor {
}
}
- header.add("errors", KnownErr.formatForResponseHeader(knownErrors));
+ header.add("errors", ToleratedUpdateError.formatForResponseHeader(knownErrors));
// include in response so client knows what effective value was (may have been server side config)
header.add("maxErrors", maxErrors);
@@ -364,7 +368,7 @@ public class TolerantUpdateProcessor extends UpdateRequestProcessor {
* Annotates the first exception (which may already have been thrown, or be thrown in the future) with
* the metadata from this update processor. For use in {@link TolerantUpdateProcessor#finish}
*/
- public void annotate(List<KnownErr> errors) {
+ public void annotate(List<ToleratedUpdateError> errors) {
if (null == first) {
return; // no exception to annotate
@@ -378,8 +382,8 @@ public class TolerantUpdateProcessor extends UpdateRequestProcessor {
first.setMetadata(firstErrMetadata);
}
- for (KnownErr ke : errors) {
- firstErrMetadata.add(ke.getMetadataKey(), ke.getMetadataValue());
+ for (ToleratedUpdateError te : errors) {
+ firstErrMetadata.add(te.getMetadataKey(), te.getMetadataValue());
}
}
@@ -388,91 +392,5 @@ public class TolerantUpdateProcessor extends UpdateRequestProcessor {
public SolrException getFirst() {
return first;
}
-
- }
-
- /**
- * Helper class for dealing with SolrException metadata (String) keys
- */
- public static final class KnownErr {
-
- private final static String META_PRE = TolerantUpdateProcessor.class.getName() + "--";
- private final static int META_PRE_LEN = META_PRE.length();
-
- /** returns a map of simple objects suitable for putting in a SolrQueryResponse */
- public static List<SimpleOrderedMap<String>> formatForResponseHeader(List<KnownErr> errs) {
- List<SimpleOrderedMap<String>> result = new ArrayList<>(errs.size());
- for (KnownErr e : errs) {
- SimpleOrderedMap<String> entry = new SimpleOrderedMap<String>();
- entry.add("type", e.type.toString());
- entry.add("id", e.id);
- entry.add("message", e.errorValue);
- result.add(entry);
- }
- return result;
- }
-
- /** returns a KnownErr instance if this metadataKey is one we care about, else null */
- public static KnownErr parseMetadataIfKnownErr(String metadataKey, String metadataVal) {
- if (! metadataKey.startsWith(META_PRE)) {
- return null; // not a key we care about
- }
- final int typeEnd = metadataKey.indexOf(':', META_PRE_LEN);
- assert 0 < typeEnd; // nocommit: better error handling
- return new KnownErr(CmdType.valueOf(metadataKey.substring(META_PRE_LEN, typeEnd)),
- metadataKey.substring(typeEnd+1), metadataVal);
- }
-
- public final CmdType type;
- /** may be null depending on type */
- public final String id;
- public final String errorValue; // nocommit: refactor: rename errMessage?
-
- public KnownErr(CmdType type, String id, String errorValue) {
- this.type = type;
- assert null != type;
-
- assert null != id;
- this.id = id;
-
- assert null != errorValue;
- this.errorValue = errorValue;
- }
-
- public String getMetadataKey() {
- return META_PRE + type + ":" + id;
- }
- public String getMetadataValue() {
- return errorValue.toString();
- }
- public String toString() {
- return getMetadataKey() + "=>" + getMetadataValue();
- }
- public int hashCode() {
- int h = this.getClass().hashCode();
- h = h * 31 + type.hashCode();
- h = h * 31 + id.hashCode();
- h = h * 31 + errorValue.hashCode();
- return h;
- }
- public boolean equals(Object o) {
- if (o instanceof KnownErr) {
- KnownErr that = (KnownErr)o;
- return that.type.equals(this.type)
- && that.id.equals(this.id)
- && that.errorValue.equals(this.errorValue);
- }
- return false;
- }
- }
-
- /**
- * Helper class for dealing with SolrException metadata (String) keys
- */
- public static enum CmdType {
- ADD, DELID, DELQ; // nocommit: others supported types? (commit?) ..
-
- // if we add support for things like commit, parsing/toString/hashCode logic
- // needs to be smarter to account for 'id' being null ... "usesId" should be a prop of enum instances
}
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c37d5a86/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorCloud.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorCloud.java b/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorCloud.java
index bee23a7..93200d8 100644
--- a/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorCloud.java
+++ b/solr/core/src/test/org/apache/solr/cloud/TestTolerantUpdateProcessorCloud.java
@@ -39,6 +39,8 @@ import org.apache.solr.common.SolrDocumentList;
import org.apache.solr.common.SolrInputDocument;
import org.apache.solr.common.SolrInputField;
import org.apache.solr.common.SolrException;
+import org.apache.solr.common.ToleratedUpdateError;
+import org.apache.solr.common.ToleratedUpdateError.CmdType;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.Replica;
import org.apache.solr.common.cloud.Slice;
@@ -49,9 +51,6 @@ import org.apache.solr.common.util.NamedList;
import org.apache.solr.common.util.SimpleOrderedMap;
import org.apache.solr.util.RevertDefaultThreadHandlerRule;
-import org.apache.solr.update.processor.TolerantUpdateProcessor.KnownErr;
-import org.apache.solr.update.processor.TolerantUpdateProcessor.CmdType;
-
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
@@ -536,11 +535,13 @@ public class TestTolerantUpdateProcessorCloud extends SolrCloudTestCase {
// verify that the Exceptions metadata can tell us what failed.
NamedList<String> remoteErrMetadata = e.getMetadata();
assertNotNull("no metadata in: " + e.toString(), remoteErrMetadata);
- Set<KnownErr> actualKnownErrs = new LinkedHashSet<KnownErr>(remoteErrMetadata.size());
+ Set<ToleratedUpdateError> actualKnownErrs
+ = new LinkedHashSet<ToleratedUpdateError>(remoteErrMetadata.size());
int actualKnownErrsCount = 0;
for (int i = 0; i < remoteErrMetadata.size(); i++) {
- KnownErr err = KnownErr.parseMetadataIfKnownErr(remoteErrMetadata.getName(i),
- remoteErrMetadata.getVal(i));
+ ToleratedUpdateError err =
+ ToleratedUpdateError.parseMetadataIfToleratedUpdateError(remoteErrMetadata.getName(i),
+ remoteErrMetadata.getVal(i));
if (null == err) {
// some metadata unrelated to this update processor
continue;
@@ -552,7 +553,7 @@ public class TestTolerantUpdateProcessorCloud extends SolrCloudTestCase {
11, actualKnownErrsCount);
assertEquals("at least one dup error in metadata: " + remoteErrMetadata.toString(),
actualKnownErrsCount, actualKnownErrs.size());
- for (KnownErr err : actualKnownErrs) {
+ for (ToleratedUpdateError err : actualKnownErrs) {
assertEquals("only expected type of error is ADD: " + err,
CmdType.ADD, err.type);
assertTrue("failed err msg didn't match expected value: " + err,
@@ -609,11 +610,13 @@ public class TestTolerantUpdateProcessorCloud extends SolrCloudTestCase {
// verify that the Exceptions metadata can tell us what failed.
NamedList<String> remoteErrMetadata = e.getMetadata();
assertNotNull("no metadata in: " + e.toString(), remoteErrMetadata);
- Set<KnownErr> actualKnownErrs = new LinkedHashSet<KnownErr>(remoteErrMetadata.size());
+ Set<ToleratedUpdateError> actualKnownErrs
+ = new LinkedHashSet<ToleratedUpdateError>(remoteErrMetadata.size());
int actualKnownErrsCount = 0;
for (int i = 0; i < remoteErrMetadata.size(); i++) {
- KnownErr err = KnownErr.parseMetadataIfKnownErr(remoteErrMetadata.getName(i),
- remoteErrMetadata.getVal(i));
+ ToleratedUpdateError err =
+ ToleratedUpdateError.parseMetadataIfToleratedUpdateError(remoteErrMetadata.getName(i),
+ remoteErrMetadata.getVal(i));
if (null == err) {
// some metadata unrelated to this update processor
continue;
@@ -625,7 +628,7 @@ public class TestTolerantUpdateProcessorCloud extends SolrCloudTestCase {
11, actualKnownErrsCount);
assertEquals("at least one dup error in metadata: " + remoteErrMetadata.toString(),
actualKnownErrsCount, actualKnownErrs.size());
- for (KnownErr err : actualKnownErrs) {
+ for (ToleratedUpdateError err : actualKnownErrs) {
assertEquals("only expected type of error is ADD: " + err,
CmdType.ADD, err.type);
assertTrue("failed id had unexpected prefix: " + err,
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c37d5a86/solr/core/src/test/org/apache/solr/update/processor/TolerantUpdateProcessorTest.java
----------------------------------------------------------------------
diff --git a/solr/core/src/test/org/apache/solr/update/processor/TolerantUpdateProcessorTest.java b/solr/core/src/test/org/apache/solr/update/processor/TolerantUpdateProcessorTest.java
index 61dac44..7470ea0 100644
--- a/solr/core/src/test/org/apache/solr/update/processor/TolerantUpdateProcessorTest.java
+++ b/solr/core/src/test/org/apache/solr/update/processor/TolerantUpdateProcessorTest.java
@@ -30,6 +30,8 @@ import javax.xml.xpath.XPathExpressionException;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrInputDocument;
+import org.apache.solr.common.ToleratedUpdateError;
+import org.apache.solr.common.ToleratedUpdateError.CmdType;
import org.apache.solr.common.params.ModifiableSolrParams;
import org.apache.solr.common.params.SolrParams;
import org.apache.solr.common.util.SimpleOrderedMap;
@@ -40,8 +42,6 @@ import org.apache.solr.request.SolrRequestHandler;
import org.apache.solr.response.SolrQueryResponse;
import org.apache.solr.servlet.DirectSolrConnection;
import org.apache.solr.update.AddUpdateCommand;
-import org.apache.solr.update.processor.TolerantUpdateProcessor.KnownErr;
-import org.apache.solr.update.processor.TolerantUpdateProcessor.CmdType;
import org.apache.solr.util.BaseTestHarness;
import org.junit.AfterClass;
import org.junit.BeforeClass;
@@ -333,39 +333,6 @@ public class TolerantUpdateProcessorTest extends UpdateProcessorTestBase {
}
- public void testKnownErrClass() {
-
- assertNull(KnownErr.parseMetadataIfKnownErr("some other key", "some value"));
-
- for (KnownErr in : new KnownErr[] {
- new KnownErr(CmdType.ADD, "doc1", "some error"),
- new KnownErr(CmdType.DELID, "doc1", "some diff error"),
- new KnownErr(CmdType.DELQ, "-field:yakko other_field:wakko", "some other error"),
- }) {
- KnownErr out = KnownErr.parseMetadataIfKnownErr(in.getMetadataKey(), in.getMetadataValue());
- assertNotNull(out);
- assertEquals(out.type, in.type);
- assertEquals(out.id, in.id);
- assertEquals(out.errorValue, in.errorValue);
- assertEquals(out.hashCode(), in.hashCode());
- assertEquals(out.toString(), in.toString());
-
- assertEquals(out, in);
- assertEquals(in, out);
-
- }
-
- assertFalse((new KnownErr(CmdType.ADD, "doc1", "some error")).equals
- (new KnownErr(CmdType.ADD, "doc2", "some error")));
- assertFalse((new KnownErr(CmdType.ADD, "doc1", "some error")).equals
- (new KnownErr(CmdType.ADD, "doc1", "some errorxx")));
- assertFalse((new KnownErr(CmdType.ADD, "doc1", "some error")).equals
- (new KnownErr(CmdType.DELID, "doc1", "some error")));
-
-
- // nocommit: add randomized testing, particularly with non-trivial 'id' values
-
- }
public String update(String chain, String xml) {
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c37d5a86/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java
index 655844f..febb56f 100644
--- a/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java
+++ b/solr/solrj/src/java/org/apache/solr/client/solrj/impl/CloudSolrClient.java
@@ -54,6 +54,7 @@ import org.apache.solr.client.solrj.request.UpdateRequest;
import org.apache.solr.client.solrj.util.ClientUtils;
import org.apache.solr.common.SolrException;
import org.apache.solr.common.SolrException.ErrorCode;
+import org.apache.solr.common.ToleratedUpdateError;
import org.apache.solr.common.cloud.Aliases;
import org.apache.solr.common.cloud.ClusterState;
import org.apache.solr.common.cloud.DocCollection;
@@ -776,13 +777,14 @@ public class CloudSolrClient extends SolrClient {
if (null != toleratedErrors) {
cheader.add("errors", toleratedErrors);
if (maxToleratedErrors < toleratedErrors.size()) {
+ // cumulative errors are too high, we need to throw a client exception w/correct metadata
+
NamedList metadata = new NamedList<String>();
SolrException toThrow = new SolrException(ErrorCode.BAD_REQUEST, "nocommit: need better msg");
toThrow.setMetadata(metadata);
for (SimpleOrderedMap<String> err : toleratedErrors) {
- // nocommit: hack, refactor KnownErr into solr-common and re-use here...
- metadata.add("org.apache.solr.update.processor.TolerantUpdateProcessor--" +
- err.get("type") + ":" + err.get("id"), err.get("message"));
+ ToleratedUpdateError te = ToleratedUpdateError.parseMap(err);
+ metadata.add(te.getMetadataKey(), te.getMetadataValue());
}
throw toThrow;
}
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c37d5a86/solr/solrj/src/java/org/apache/solr/common/ToleratedUpdateError.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/java/org/apache/solr/common/ToleratedUpdateError.java b/solr/solrj/src/java/org/apache/solr/common/ToleratedUpdateError.java
new file mode 100644
index 0000000..7261a21
--- /dev/null
+++ b/solr/solrj/src/java/org/apache/solr/common/ToleratedUpdateError.java
@@ -0,0 +1,150 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.common;
+
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.solr.common.util.SimpleOrderedMap;
+
+
+/**
+ * nocommit: more javadocs, mention (but obviously no link) to TolerantUpdateProcessor
+ */
+public final class ToleratedUpdateError {
+
+ private final static String META_PRE = ToleratedUpdateError.class.getName() + "--";
+ private final static int META_PRE_LEN = META_PRE.length();
+
+ /**
+ * returns a list of maps of simple objects suitable for putting in a SolrQueryResponse header
+ * @see #getSimpleMap
+ * @see #parseMap
+ */
+ public static List<SimpleOrderedMap<String>> formatForResponseHeader(List<ToleratedUpdateError> errs) {
+ List<SimpleOrderedMap<String>> result = new ArrayList<>(errs.size());
+ for (ToleratedUpdateError e : errs) {
+ result.add(e.getSimpleMap());
+ }
+ return result;
+ }
+
+ /**
+ * returns a ToleratedUpdateError instance from the data in this Map
+ * @see #getSimpleMap
+ */
+ public static ToleratedUpdateError parseMap(SimpleOrderedMap<String> data) {
+ // nocommit: error handling and clean exception reporting if data is bogus
+ return new ToleratedUpdateError(CmdType.valueOf(data.get("type")), data.get("id"), data.get("message"));
+ }
+
+ /**
+ * returns a ToleratedUpdateError instance if this metadataKey is one we care about, else null
+ * @see #getMetadataKey
+ * @see #getMetadataValue
+ */
+ public static ToleratedUpdateError parseMetadataIfToleratedUpdateError(String metadataKey,
+ String metadataVal) {
+ if (! metadataKey.startsWith(META_PRE)) {
+ return null; // not a key we care about
+ }
+ final int typeEnd = metadataKey.indexOf(':', META_PRE_LEN);
+ assert 0 < typeEnd; // nocommit: better error handling
+ return new ToleratedUpdateError(CmdType.valueOf(metadataKey.substring(META_PRE_LEN, typeEnd)),
+ metadataKey.substring(typeEnd+1), metadataVal);
+ }
+
+ // nocommit: make these private & provide getter methods
+ public final CmdType type;
+ public final String id; // may be null depending on type
+ public final String errorValue; // nocommit: refactor: rename message?
+
+ public ToleratedUpdateError(CmdType type, String id, String errorValue) {
+ this.type = type;
+ assert null != type;
+
+ assert null != id;
+ this.id = id;
+
+ assert null != errorValue;
+ this.errorValue = errorValue;
+ }
+
+ /**
+ * returns a string suitable for use as a key in {@link SolrException#setMetadata}
+ *
+ * @see #parseMetadataIfToleratedUpdateError
+ */
+ public String getMetadataKey() {
+ return META_PRE + type + ":" + id;
+ }
+
+ /**
+ * returns a string suitable for use as a value in {@link SolrException#setMetadata}
+ *
+ * @see #parseMetadataIfToleratedUpdateError
+ */
+ public String getMetadataValue() {
+ return errorValue.toString();
+ }
+
+ /**
+ * returns a map of simple objects suitable for putting in a SolrQueryResponse header
+ * @see #formatForResponseHeader
+ * @see #parseMap
+ */
+ public SimpleOrderedMap<String> getSimpleMap() {
+ SimpleOrderedMap<String> entry = new SimpleOrderedMap<String>();
+ entry.add("type", type.toString());
+ entry.add("id", id);
+ entry.add("message", errorValue);
+ return entry;
+ }
+
+ public String toString() {
+ return getMetadataKey() + "=>" + getMetadataValue();
+ }
+
+ public int hashCode() {
+ int h = this.getClass().hashCode();
+ h = h * 31 + type.hashCode();
+ h = h * 31 + id.hashCode();
+ h = h * 31 + errorValue.hashCode();
+ return h;
+ }
+
+ public boolean equals(Object o) {
+ if (o instanceof ToleratedUpdateError) {
+ ToleratedUpdateError that = (ToleratedUpdateError)o;
+ return that.type.equals(this.type)
+ && that.id.equals(this.id)
+ && that.errorValue.equals(this.errorValue);
+ }
+ return false;
+ }
+
+ /**
+ * Helper class for dealing with SolrException metadata (String) keys
+ */
+ public static enum CmdType {
+ ADD, DELID, DELQ;
+
+ // if we add support for things like commit, parsing/toString/hashCode logic
+ // needs to be smarter to account for 'id' being null ... "usesId" should be a prop of enum instances
+ }
+}
+
+
http://git-wip-us.apache.org/repos/asf/lucene-solr/blob/c37d5a86/solr/solrj/src/test/org/apache/solr/common/TestToleratedUpdateError.java
----------------------------------------------------------------------
diff --git a/solr/solrj/src/test/org/apache/solr/common/TestToleratedUpdateError.java b/solr/solrj/src/test/org/apache/solr/common/TestToleratedUpdateError.java
new file mode 100644
index 0000000..6759b79
--- /dev/null
+++ b/solr/solrj/src/test/org/apache/solr/common/TestToleratedUpdateError.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.solr.common;
+
+import org.apache.solr.common.ToleratedUpdateError;
+import org.apache.solr.common.ToleratedUpdateError.CmdType;
+
+import org.apache.lucene.util.LuceneTestCase;
+
+/** Basic testing of the serialization/encapsulation code in ToleratedUpdateError */
+public class TestToleratedUpdateError extends LuceneTestCase {
+
+ // nocommit: add randomized testing, particularly with non-trivial 'id' values
+
+ public void checkRoundTripComparisons(Coppier coppier) {
+
+ assertNull(ToleratedUpdateError.parseMetadataIfToleratedUpdateError("some other key", "some value"));
+
+ for (ToleratedUpdateError in : new ToleratedUpdateError[] {
+ new ToleratedUpdateError(CmdType.ADD, "doc1", "some error"),
+ new ToleratedUpdateError(CmdType.DELID, "doc1", "some diff error"),
+ new ToleratedUpdateError(CmdType.DELQ, "-field:yakko other_field:wakko", "some other error"),
+ }) {
+
+ ToleratedUpdateError out = coppier.copy(in);
+
+ assertNotNull(out);
+ assertEquals(out.type, in.type);
+ assertEquals(out.id, in.id);
+ assertEquals(out.errorValue, in.errorValue);
+ assertEquals(out.hashCode(), in.hashCode());
+ assertEquals(out.toString(), in.toString());
+
+ assertEquals(in.getMetadataKey(), out.getMetadataKey());
+ assertEquals(in.getMetadataValue(), out.getMetadataValue());
+
+ assertEquals(out, in);
+ assertEquals(in, out);
+
+ }
+
+ assertFalse((new ToleratedUpdateError(CmdType.ADD, "doc1", "some error")).equals
+ (new ToleratedUpdateError(CmdType.ADD, "doc2", "some error")));
+ assertFalse((new ToleratedUpdateError(CmdType.ADD, "doc1", "some error")).equals
+ (new ToleratedUpdateError(CmdType.ADD, "doc1", "some errorxx")));
+ assertFalse((new ToleratedUpdateError(CmdType.ADD, "doc1", "some error")).equals
+ (new ToleratedUpdateError(CmdType.DELID, "doc1", "some error")));
+
+ }
+
+ public void testMetadataRoundTripComparisons(Coppier coppier) {
+ checkRoundTripComparisons(new Coppier() {
+ public ToleratedUpdateError copy(ToleratedUpdateError in) {
+ return ToleratedUpdateError.parseMetadataIfToleratedUpdateError
+ (in.getMetadataKey(), in.getMetadataValue());
+ }
+ });
+ }
+
+ public void testMapRoundTripComparisons() {
+ checkRoundTripComparisons(new Coppier() {
+ public ToleratedUpdateError copy(ToleratedUpdateError in) {
+ return ToleratedUpdateError.parseMap(in.getSimpleMap());
+ }
+ });
+ }
+
+ private static abstract class Coppier {
+ public abstract ToleratedUpdateError copy(ToleratedUpdateError in);
+ }
+}
+
+
+
+