summaryrefslogtreecommitdiffstats
path: root/persistence
diff options
context:
space:
mode:
authorTor Brede Vekterli <vekterli@oath.com>2018-11-26 13:51:12 +0000
committerTor Brede Vekterli <vekterli@oath.com>2018-11-26 14:12:23 +0000
commitb71cc013e878e4a12ee3ce6c7434424fcb7f204b (patch)
tree7986f84c321d3607b9f9389213fb9bd2c7a94dd5 /persistence
parent9871bb9e867198d767386d35a3842a2da8fc7dfb (diff)
Support test-and-set for auto-create document updates
Has the obvious consistency caveats that if all your existing replicas are down, the update will go through since the document from an weak consistency perspective does not exist anywhere. But can be a useful feature if this is an acceptable tradeoff.
Diffstat (limited to 'persistence')
-rw-r--r--persistence/src/vespa/persistence/conformancetest/conformancetest.cpp27
-rw-r--r--persistence/src/vespa/persistence/spi/abstractpersistenceprovider.cpp20
2 files changed, 40 insertions, 7 deletions
diff --git a/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp b/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp
index c1373a391f0..4d9d48c4926 100644
--- a/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp
+++ b/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp
@@ -948,7 +948,6 @@ void ConformanceTest::testUpdate() {
CPPUNIT_ASSERT(!result.hasDocument());
}
-
{
UpdateResult result = spi->update(bucket, Timestamp(6), update,
context);
@@ -957,6 +956,32 @@ void ConformanceTest::testUpdate() {
CPPUNIT_ASSERT_EQUAL(Result::NONE, result.getErrorCode());
CPPUNIT_ASSERT_EQUAL(Timestamp(0), result.getExistingTimestamp());
}
+
+ {
+ GetResult result = spi->get(bucket, document::AllFields(), doc1->getId(), context);
+ CPPUNIT_ASSERT_EQUAL(Result::NONE, result.getErrorCode());
+ CPPUNIT_ASSERT_EQUAL(Timestamp(0), result.getTimestamp());
+ CPPUNIT_ASSERT(!result.hasDocument());
+ }
+
+ update->setCreateIfNonExistent(true);
+ {
+ // Document does not exist (and therefore its condition cannot match by definition),
+ // but since CreateIfNonExistent is set it should be auto-created anyway.
+ UpdateResult result = spi->update(bucket, Timestamp(7), update, context);
+ spi->flush(bucket, context);
+ CPPUNIT_ASSERT_EQUAL(Result::NONE, result.getErrorCode());
+ CPPUNIT_ASSERT_EQUAL(Timestamp(7), result.getExistingTimestamp());
+ }
+
+ {
+ GetResult result = spi->get(bucket, document::AllFields(), doc1->getId(), context);
+ CPPUNIT_ASSERT_EQUAL(Result::NONE, result.getErrorCode());
+ CPPUNIT_ASSERT_EQUAL(Timestamp(7), result.getTimestamp());
+ CPPUNIT_ASSERT_EQUAL(document::IntFieldValue(42),
+ reinterpret_cast<document::IntFieldValue&>(
+ *result.getDocument().getValue("headerval")));
+ }
}
void ConformanceTest::testGet() {
diff --git a/persistence/src/vespa/persistence/spi/abstractpersistenceprovider.cpp b/persistence/src/vespa/persistence/spi/abstractpersistenceprovider.cpp
index 5e6e908e042..7f6bd835cd5 100644
--- a/persistence/src/vespa/persistence/spi/abstractpersistenceprovider.cpp
+++ b/persistence/src/vespa/persistence/spi/abstractpersistenceprovider.cpp
@@ -1,9 +1,10 @@
// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "abstractpersistenceprovider.h"
+#include <vespa/document/datatype/documenttype.h>
#include <vespa/document/update/documentupdate.h>
#include <vespa/document/fieldset/fieldsets.h>
-
+#include <vespa/document/fieldvalue/document.h>
namespace storage {
@@ -19,20 +20,27 @@ AbstractPersistenceProvider::update(const Bucket& bucket, Timestamp ts,
return UpdateResult(getResult.getErrorCode(), getResult.getErrorMessage());
}
- if (!getResult.hasDocument()) {
- return UpdateResult();
+ auto docToUpdate = getResult.getDocumentPtr();
+ Timestamp updatedTs = getResult.getTimestamp();
+ if (!docToUpdate) {
+ if (!upd->getCreateIfNonExistent()) {
+ return UpdateResult();
+ } else {
+ docToUpdate = std::make_shared<document::Document>(upd->getType(), upd->getId());
+ updatedTs = ts;
+ }
}
- upd->applyTo(getResult.getDocument());
+ upd->applyTo(*docToUpdate);
- Result putResult = put(bucket, ts, getResult.getDocumentPtr(), context);
+ Result putResult = put(bucket, ts, docToUpdate, context);
if (putResult.hasError()) {
return UpdateResult(putResult.getErrorCode(),
putResult.getErrorMessage());
}
- return UpdateResult(getResult.getTimestamp());
+ return UpdateResult(updatedTs);
}
RemoveResult