diff --git a/solr/CHANGES.txt b/solr/CHANGES.txt index fcf1f9c69fd..da63c93b544 100644 --- a/solr/CHANGES.txt +++ b/solr/CHANGES.txt @@ -86,6 +86,10 @@ Bug Fixes * SOLR-12035: ExtendedDismaxQParser fails to include charfilters in nostopanalyzer (Tim Allison via Tomás Fernández Löbbe) +* SOLR-10734: AtomicUpdateRequestProcessor can cause wrong/old values to be set under concurrent updates for the same + document. Multithreaded test for AtomicUpdateRequestProcessor was also beefed up and fixed. + (Ishan Chattopadhyaya, Noble Paul, Amrit Sarkar, shalin) + Optimizations ---------------------- @@ -122,8 +126,6 @@ Other Changes * SOLR-12118: Solr Ref-Guide can now use some ivy version props directly as attributes in content (hossman) -* SOLR-10734: Multithreaded test/support for AtomicURP broken. (Ishan Chattopadhyaya, Noble Paul, Amrit Sarkar, shalin) - ================== 7.3.0 ================== Consult the LUCENE_CHANGES.txt file for additional, low level, changes in this release. diff --git a/solr/core/src/java/org/apache/solr/update/processor/AtomicUpdateProcessorFactory.java b/solr/core/src/java/org/apache/solr/update/processor/AtomicUpdateProcessorFactory.java index 84bf03a1bc9..c3522f06cdd 100644 --- a/solr/core/src/java/org/apache/solr/update/processor/AtomicUpdateProcessorFactory.java +++ b/solr/core/src/java/org/apache/solr/update/processor/AtomicUpdateProcessorFactory.java @@ -153,17 +153,17 @@ public class AtomicUpdateProcessorFactory extends UpdateRequestProcessorFactory // if atomic, put _version_ for optimistic concurrency if doc present in index if (isAtomicUpdateAddedByMe) { Long lastVersion = vinfo.lookupVersion(cmd.getIndexedId()); - if (lastVersion != null) { - orgdoc.setField(VERSION, lastVersion); - } - processAddWithRetry(cmd, 0); + // if lastVersion is null then we put -1 to assert that document must not exist + lastVersion = lastVersion == null ? -1 : lastVersion; + orgdoc.setField(VERSION, lastVersion); + processAddWithRetry(cmd, 1, cmd.getSolrInputDocument().deepCopy()); } else { super.processAdd(cmd); } // else send it for doc to get inserted for the first time } - private void processAddWithRetry(AddUpdateCommand cmd, int attempts) throws IOException { + private void processAddWithRetry(AddUpdateCommand cmd, int attempts, SolrInputDocument clonedOriginalDoc) throws IOException { try { super.processAdd(cmd); } catch (SolrException e) { @@ -174,11 +174,18 @@ public class AtomicUpdateProcessorFactory extends UpdateRequestProcessorFactory if (e.code() == ErrorCode.CONFLICT.code) { // version conflict log.warn("Atomic update failed due to " + e.getMessage() + " Retrying with new version .... (" + attempts + ")"); + Long lastVersion = vinfo.lookupVersion(cmd.getIndexedId()); - if (lastVersion != null) { - cmd.solrDoc.setField(VERSION, lastVersion); - } - processAddWithRetry(cmd, attempts); + // if lastVersion is null then we put -1 to assert that document must not exist + lastVersion = lastVersion == null ? -1 : lastVersion; + + // The AtomicUpdateDocumentMerger modifies the AddUpdateCommand.solrDoc to populate the real values of the + // modified fields. We don't want those absolute values because they are out-of-date due to the conflict + // so we restore the original document created in processAdd method and set the right version on it + cmd.solrDoc = clonedOriginalDoc; + cmd.solrDoc.setField(VERSION, lastVersion); + + processAddWithRetry(cmd, attempts, clonedOriginalDoc); } } } diff --git a/solr/core/src/test/org/apache/solr/update/processor/AtomicUpdateProcessorFactoryTest.java b/solr/core/src/test/org/apache/solr/update/processor/AtomicUpdateProcessorFactoryTest.java index 92a16d864f7..7d377fa9e09 100644 --- a/solr/core/src/test/org/apache/solr/update/processor/AtomicUpdateProcessorFactoryTest.java +++ b/solr/core/src/test/org/apache/solr/update/processor/AtomicUpdateProcessorFactoryTest.java @@ -198,7 +198,6 @@ public class AtomicUpdateProcessorFactoryTest extends SolrTestCaseJ4 { } - @BadApple(bugUrl = "https://issues.apache.org/jira/browse/SOLR-10734") public void testMultipleThreads() throws Exception { clearIndex(); String[] strings = new String[5];