diff options
author | Henning Baldersheim <balder@oath.com> | 2018-06-07 07:34:57 +0200 |
---|---|---|
committer | Henning Baldersheim <balder@oath.com> | 2018-06-12 22:50:28 +0200 |
commit | 6c04171843d0d9ebc99f6b91303a76c62eb2aef4 (patch) | |
tree | 338ffa8e190c93ef4abab1ebd1ac79036c74cfd2 /document | |
parent | 047ea0bed80966554e29a1db1b35361d946a3866 (diff) |
1 - Use a backing buffer for the DocumentUpdate that always is source of truth.
2 - Use this buffer for re-serialization.
3 - Make deserialization lazy where possible.
Currently lazy on replay and when arriving over the storageapi.
Still needs to eager over documentapi.
4 - Deserialize eagerly in the persistence thread since those are plentyfull and not bottlenecked,
instead of in the single master thread.
Use real repo.
Diffstat (limited to 'document')
-rw-r--r-- | document/src/tests/documentselectparsertest.cpp | 3 | ||||
-rw-r--r-- | document/src/tests/documentupdatetestcase.cpp | 275 | ||||
-rw-r--r-- | document/src/tests/fieldpathupdatetestcase.cpp | 82 | ||||
-rw-r--r-- | document/src/tests/testxml.cpp | 2 | ||||
-rw-r--r-- | document/src/vespa/document/base/forcelink.cpp | 2 | ||||
-rw-r--r-- | document/src/vespa/document/serialization/vespadocumentserializer.cpp | 14 | ||||
-rw-r--r-- | document/src/vespa/document/update/documentupdate.cpp | 282 | ||||
-rw-r--r-- | document/src/vespa/document/update/documentupdate.h | 75 |
8 files changed, 386 insertions, 349 deletions
diff --git a/document/src/tests/documentselectparsertest.cpp b/document/src/tests/documentselectparsertest.cpp index 05ec2ce99d0..2433bfecdab 100644 --- a/document/src/tests/documentselectparsertest.cpp +++ b/document/src/tests/documentselectparsertest.cpp @@ -163,8 +163,7 @@ DocumentUpdate::SP DocumentSelectParserTest::createUpdate( const std::string& hstr) { const DocumentType* type = _repo->getDocumentType(doctype); - DocumentUpdate::SP doc( - new DocumentUpdate(*type, DocumentId(id))); + DocumentUpdate::SP doc(new DocumentUpdate(*_repo, *type, DocumentId(id))); doc->addUpdate(FieldUpdate(doc->getType().getField("headerval")) .addUpdate(AssignValueUpdate(IntFieldValue(hint)))); doc->addUpdate(FieldUpdate(doc->getType().getField("hstringval")) diff --git a/document/src/tests/documentupdatetestcase.cpp b/document/src/tests/documentupdatetestcase.cpp index 9ba17d95264..2a77d610420 100644 --- a/document/src/tests/documentupdatetestcase.cpp +++ b/document/src/tests/documentupdatetestcase.cpp @@ -191,16 +191,15 @@ DocumentUpdateTest::testSimpleUsage() { fieldUpdate.addUpdate(AssignValueUpdate(IntFieldValue(1))); ByteBuffer::UP fieldBuf = serialize(fieldUpdate); fieldBuf->flip(); - FieldUpdate fieldUpdateCopy(repo, *docType, *fieldBuf, - Document::getNewestSerializationVersion()); + FieldUpdate fieldUpdateCopy(repo, *docType, *fieldBuf, Document::getNewestSerializationVersion()); CPPUNIT_ASSERT_EQUAL(fieldUpdate, fieldUpdateCopy); // Test that a document update can be serialized - DocumentUpdate docUpdate(*docType, DocumentId("doc::testdoc")); + DocumentUpdate docUpdate(repo, *docType, DocumentId("doc::testdoc")); docUpdate.addUpdate(fieldUpdateCopy); - ByteBuffer::UP docBuf = serialize42(docUpdate); + ByteBuffer::UP docBuf = serializeHEAD(docUpdate); docBuf->flip(); - DocumentUpdate::UP docUpdateCopy(DocumentUpdate::create42(repo, *docBuf)); + auto docUpdateCopy(DocumentUpdate::createHEAD(repo, nbostream(docBuf->getBufferAtPos(), docBuf->getRemaining()))); // Create a test document Document doc(*docType, DocumentId("doc::testdoc")); @@ -214,62 +213,53 @@ DocumentUpdateTest::testSimpleUsage() { // Verify that we can apply simple updates to it { Document updated(doc); - DocumentUpdate upd(*docType, DocumentId("doc::testdoc")); - upd.addUpdate(FieldUpdate(docType->getField("intf")) - .addUpdate(ClearValueUpdate())); + DocumentUpdate upd(repo, *docType, DocumentId("doc::testdoc")); + upd.addUpdate(FieldUpdate(docType->getField("intf")).addUpdate(ClearValueUpdate())); upd.applyTo(updated); CPPUNIT_ASSERT(doc != updated); CPPUNIT_ASSERT(! updated.getValue("intf")); } { Document updated(doc); - DocumentUpdate upd(*docType, DocumentId("doc::testdoc")); - upd.addUpdate(FieldUpdate(docType->getField("intf")) - .addUpdate(AssignValueUpdate(IntFieldValue(15)))); + DocumentUpdate upd(repo, *docType, DocumentId("doc::testdoc")); + upd.addUpdate(FieldUpdate(docType->getField("intf")).addUpdate(AssignValueUpdate(IntFieldValue(15)))); upd.applyTo(updated); CPPUNIT_ASSERT(doc != updated); CPPUNIT_ASSERT_EQUAL(15, updated.getValue("intf")->getAsInt()); } { Document updated(doc); - DocumentUpdate upd(*docType, DocumentId("doc::testdoc")); - upd.addUpdate(FieldUpdate(docType->getField("intf")) - .addUpdate(ArithmeticValueUpdate( - ArithmeticValueUpdate::Add, 15))); + DocumentUpdate upd(repo, *docType, DocumentId("doc::testdoc")); + upd.addUpdate(FieldUpdate(docType->getField("intf")).addUpdate(ArithmeticValueUpdate(ArithmeticValueUpdate::Add, 15))); upd.applyTo(updated); CPPUNIT_ASSERT(doc != updated); CPPUNIT_ASSERT_EQUAL(20, updated.getValue("intf")->getAsInt()); } { Document updated(doc); - DocumentUpdate upd(*docType, DocumentId("doc::testdoc")); - upd.addUpdate(FieldUpdate(docType->getField("intarr")) - .addUpdate(AddValueUpdate(IntFieldValue(4)))); + DocumentUpdate upd(repo, *docType, DocumentId("doc::testdoc")); + upd.addUpdate(FieldUpdate(docType->getField("intarr")).addUpdate(AddValueUpdate(IntFieldValue(4)))); upd.applyTo(updated); CPPUNIT_ASSERT(doc != updated); - std::unique_ptr<ArrayFieldValue> val(dynamic_cast<ArrayFieldValue*>( - updated.getValue("intarr").release())); + std::unique_ptr<ArrayFieldValue> val(dynamic_cast<ArrayFieldValue*>(updated.getValue("intarr").release())); CPPUNIT_ASSERT_EQUAL(size_t(3), val->size()); CPPUNIT_ASSERT_EQUAL(4, (*val)[2].getAsInt()); } { Document updated(doc); - DocumentUpdate upd(*docType, DocumentId("doc::testdoc")); - upd.addUpdate(FieldUpdate(docType->getField("intarr")) - .addUpdate(RemoveValueUpdate(IntFieldValue(3)))); + DocumentUpdate upd(repo, *docType, DocumentId("doc::testdoc")); + upd.addUpdate(FieldUpdate(docType->getField("intarr")).addUpdate(RemoveValueUpdate(IntFieldValue(3)))); upd.applyTo(updated); CPPUNIT_ASSERT(doc != updated); - std::unique_ptr<ArrayFieldValue> val(dynamic_cast<ArrayFieldValue*>( - updated.getValue("intarr").release())); + std::unique_ptr<ArrayFieldValue> val(dynamic_cast<ArrayFieldValue*>(updated.getValue("intarr").release())); CPPUNIT_ASSERT_EQUAL(size_t(1), val->size()); CPPUNIT_ASSERT_EQUAL(7, (*val)[0].getAsInt()); } { Document updated(doc); - DocumentUpdate upd(*docType, DocumentId("doc::testdoc")); + DocumentUpdate upd(repo, *docType, DocumentId("doc::testdoc")); upd.addUpdate(FieldUpdate(docType->getField("bytef")) - .addUpdate(ArithmeticValueUpdate( - ArithmeticValueUpdate::Add, 15))); + .addUpdate(ArithmeticValueUpdate(ArithmeticValueUpdate::Add, 15))); upd.applyTo(updated); CPPUNIT_ASSERT(doc != updated); CPPUNIT_ASSERT_EQUAL(15, (int) updated.getValue("bytef")->getAsByte()); @@ -286,9 +276,8 @@ DocumentUpdateTest::testClearField() CPPUNIT_ASSERT_EQUAL(4, doc->getValue("headerval")->getAsInt()); // Apply an update. - DocumentUpdate(*doc->getDataType(), doc->getId()) - .addUpdate(FieldUpdate(doc->getField("headerval")) - .addUpdate(AssignValueUpdate())) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) + .addUpdate(FieldUpdate(doc->getField("headerval")).addUpdate(AssignValueUpdate())) .applyTo(*doc); CPPUNIT_ASSERT(!doc->getValue("headerval")); } @@ -303,9 +292,8 @@ DocumentUpdateTest::testUpdateApplySingleValue() CPPUNIT_ASSERT_EQUAL(4, doc->getValue("headerval")->getAsInt()); // Apply an update. - DocumentUpdate(*doc->getDataType(), doc->getId()) - .addUpdate(FieldUpdate(doc->getField("headerval")) - .addUpdate(AssignValueUpdate(IntFieldValue(9)))) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) + .addUpdate(FieldUpdate(doc->getField("headerval")).addUpdate(AssignValueUpdate(IntFieldValue(9)))) .applyTo(*doc); CPPUNIT_ASSERT_EQUAL(9, doc->getValue("headerval")->getAsInt()); } @@ -316,28 +304,23 @@ DocumentUpdateTest::testUpdateArray() // Create a document. TestDocMan docMan; Document::UP doc(docMan.createDocument()); - CPPUNIT_ASSERT_EQUAL((document::FieldValue*)NULL, - doc->getValue(doc->getField("tags")).get()); + CPPUNIT_ASSERT_EQUAL((document::FieldValue*)NULL, doc->getValue(doc->getField("tags")).get()); // Assign array field. ArrayFieldValue myarray(doc->getType().getField("tags").getDataType()); myarray.add(StringFieldValue("foo")); myarray.add(StringFieldValue("bar")); - DocumentUpdate(*doc->getDataType(), doc->getId()) - .addUpdate(FieldUpdate(doc->getField("tags")) - .addUpdate(AssignValueUpdate(myarray))) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) + .addUpdate(FieldUpdate(doc->getField("tags")).addUpdate(AssignValueUpdate(myarray))) .applyTo(*doc); - std::unique_ptr<ArrayFieldValue> - fval1(doc->getAs<ArrayFieldValue>(doc->getField("tags"))); + auto fval1(doc->getAs<ArrayFieldValue>(doc->getField("tags"))); CPPUNIT_ASSERT_EQUAL((size_t) 2, fval1->size()); - CPPUNIT_ASSERT_EQUAL(std::string("foo"), - std::string((*fval1)[0].getAsString())); - CPPUNIT_ASSERT_EQUAL(std::string("bar"), - std::string((*fval1)[1].getAsString())); + CPPUNIT_ASSERT_EQUAL(std::string("foo"), std::string((*fval1)[0].getAsString())); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), std::string((*fval1)[1].getAsString())); // Append array field - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(doc->getField("tags")) .addUpdate(AddValueUpdate(StringFieldValue("another"))) .addUpdate(AddValueUpdate(StringFieldValue("tag")))) @@ -345,21 +328,16 @@ DocumentUpdateTest::testUpdateArray() std::unique_ptr<ArrayFieldValue> fval2(doc->getAs<ArrayFieldValue>(doc->getField("tags"))); CPPUNIT_ASSERT_EQUAL((size_t) 4, fval2->size()); - CPPUNIT_ASSERT_EQUAL(std::string("foo"), - std::string((*fval2)[0].getAsString())); - CPPUNIT_ASSERT_EQUAL(std::string("bar"), - std::string((*fval2)[1].getAsString())); - CPPUNIT_ASSERT_EQUAL(std::string("another"), - std::string((*fval2)[2].getAsString())); - CPPUNIT_ASSERT_EQUAL(std::string("tag"), - std::string((*fval2)[3].getAsString())); + CPPUNIT_ASSERT_EQUAL(std::string("foo"), std::string((*fval2)[0].getAsString())); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), std::string((*fval2)[1].getAsString())); + CPPUNIT_ASSERT_EQUAL(std::string("another"), std::string((*fval2)[2].getAsString())); + CPPUNIT_ASSERT_EQUAL(std::string("tag"), std::string((*fval2)[3].getAsString())); // Append single value. try { - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(doc->getField("tags")) - .addUpdate(AssignValueUpdate( - StringFieldValue("THROW MEH!")))) + .addUpdate(AssignValueUpdate(StringFieldValue("THROW MEH!")))) .applyTo(*doc); CPPUNIT_FAIL("Expected exception when assinging a string value to an " "array field."); @@ -369,25 +347,22 @@ DocumentUpdateTest::testUpdateArray() } // Remove array field. - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(doc->getField("tags")) .addUpdate(RemoveValueUpdate(StringFieldValue("foo"))) .addUpdate(RemoveValueUpdate(StringFieldValue("tag")))) .applyTo(*doc); - std::unique_ptr<ArrayFieldValue> - fval3(doc->getAs<ArrayFieldValue>(doc->getField("tags"))); + auto fval3(doc->getAs<ArrayFieldValue>(doc->getField("tags"))); CPPUNIT_ASSERT_EQUAL((size_t) 2, fval3->size()); - CPPUNIT_ASSERT_EQUAL(std::string("bar"), - std::string((*fval3)[0].getAsString())); - CPPUNIT_ASSERT_EQUAL(std::string("another"), - std::string((*fval3)[1].getAsString())); + CPPUNIT_ASSERT_EQUAL(std::string("bar"), std::string((*fval3)[0].getAsString())); + CPPUNIT_ASSERT_EQUAL(std::string("another"), std::string((*fval3)[1].getAsString())); // Remove array from array. ArrayFieldValue myarray2(doc->getType().getField("tags").getDataType()); myarray2.add(StringFieldValue("foo")); myarray2.add(StringFieldValue("bar")); try { - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(doc->getField("tags")) .addUpdate(RemoveValueUpdate(myarray2))) .applyTo(*doc); @@ -412,12 +387,10 @@ DocumentUpdateTest::testUpdateWeightedSet() WeightedSetFieldValue wset(field.getDataType()); wset.add(StringFieldValue("foo"), 3); wset.add(StringFieldValue("bar"), 14); - DocumentUpdate(*doc->getDataType(), doc->getId()) - .addUpdate(FieldUpdate(field) - .addUpdate(AssignValueUpdate(wset))) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) + .addUpdate(FieldUpdate(field).addUpdate(AssignValueUpdate(wset))) .applyTo(*doc); - std::unique_ptr<WeightedSetFieldValue> - fval1(doc->getAs<WeightedSetFieldValue>(field)); + auto fval1(doc->getAs<WeightedSetFieldValue>(field)); CPPUNIT_ASSERT_EQUAL((size_t) 2, fval1->size()); CPPUNIT_ASSERT(fval1->contains(StringFieldValue("foo"))); CPPUNIT_ASSERT(fval1->find(StringFieldValue("foo")) != fval1->end()); @@ -430,12 +403,11 @@ DocumentUpdateTest::testUpdateWeightedSet() WeightedSetFieldValue wset2(field.getDataType()); wset2.add(StringFieldValue("foo"), 16); wset2.add(StringFieldValue("bar"), 24); - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(field) .addUpdate(AssignValueUpdate(wset2))) .applyTo(*doc); - std::unique_ptr<WeightedSetFieldValue> - fval2(doc->getAs<WeightedSetFieldValue>(field)); + auto fval2(doc->getAs<WeightedSetFieldValue>(field)); CPPUNIT_ASSERT_EQUAL((size_t) 2, fval2->size()); CPPUNIT_ASSERT(fval2->contains(StringFieldValue("foo"))); CPPUNIT_ASSERT(fval2->find(StringFieldValue("foo")) != fval1->end()); @@ -445,12 +417,10 @@ DocumentUpdateTest::testUpdateWeightedSet() CPPUNIT_ASSERT_EQUAL(24, fval2->get(StringFieldValue("bar"), 0)); // Append weighted field - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(field) - .addUpdate(AddValueUpdate(StringFieldValue("foo")) - .setWeight(3)) - .addUpdate(AddValueUpdate(StringFieldValue("too")) - .setWeight(14))) + .addUpdate(AddValueUpdate(StringFieldValue("foo")).setWeight(3)) + .addUpdate(AddValueUpdate(StringFieldValue("too")).setWeight(14))) .applyTo(*doc); std::unique_ptr<WeightedSetFieldValue> fval3(doc->getAs<WeightedSetFieldValue>(field)); @@ -463,13 +433,12 @@ DocumentUpdateTest::testUpdateWeightedSet() CPPUNIT_ASSERT_EQUAL(14, fval3->get(StringFieldValue("too"), 0)); // Remove weighted field - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(field) .addUpdate(RemoveValueUpdate(StringFieldValue("foo"))) .addUpdate(RemoveValueUpdate(StringFieldValue("too")))) .applyTo(*doc); - std::unique_ptr<WeightedSetFieldValue> - fval4(doc->getAs<WeightedSetFieldValue>(field)); + auto fval4(doc->getAs<WeightedSetFieldValue>(field)); CPPUNIT_ASSERT_EQUAL((size_t) 1, fval4->size()); CPPUNIT_ASSERT(!fval4->contains(StringFieldValue("foo"))); CPPUNIT_ASSERT(fval4->contains(StringFieldValue("bar"))); @@ -500,21 +469,18 @@ struct WeightedSetAutoCreateFixture // and remove-if-zero attributes set. Attempting to explicitly create // a field matching those characteristics will in fact fail with a // redefinition error. - builder.document(42, "test", - Struct("test.header") - .addField("strwset", DataType::T_TAG), - Struct("test.body")); + builder.document(42, "test", Struct("test.header").addField("strwset", DataType::T_TAG), Struct("test.body")); return builder.config(); } }; -WeightedSetAutoCreateFixture::~WeightedSetAutoCreateFixture() {} +WeightedSetAutoCreateFixture::~WeightedSetAutoCreateFixture() = default; WeightedSetAutoCreateFixture::WeightedSetAutoCreateFixture() : repo(makeConfig()), docType(repo.getDocumentType("test")), doc(*docType, DocumentId("doc::testdoc")), field(docType->getField("strwset")), - update(*docType, DocumentId("doc::testdoc")) + update(repo, *docType, DocumentId("doc::testdoc")) { update.addUpdate(FieldUpdate(field) .addUpdate(MapValueUpdate(StringFieldValue("foo"), @@ -585,7 +551,8 @@ void DocumentUpdateTest::testReadSerializedFile() } close(fd); - DocumentUpdate::UP updp(DocumentUpdate::create42(repo, buf)); + nbostream is(buf.getBufferAtPos(), buf.getRemaining()); + DocumentUpdate::UP updp(DocumentUpdate::create42(repo, is)); DocumentUpdate& upd(*updp); const DocumentType *type = repo.getDocumentType("serializetest"); @@ -647,7 +614,7 @@ void DocumentUpdateTest::testGenerateSerializedFile() DocumentTypeRepo repo(readDocumenttypesConfig(file_name)); const DocumentType *type(repo.getDocumentType("serializetest")); - DocumentUpdate upd(*type, DocumentId(DocIdString("update", "test"))); + DocumentUpdate upd(repo, *type, DocumentId(DocIdString("update", "test"))); upd.addUpdate(FieldUpdate(type->getField("intfield")) .addUpdate(AssignValueUpdate(IntFieldValue(4)))); upd.addUpdate(FieldUpdate(type->getField("floatfield")) @@ -678,11 +645,10 @@ void DocumentUpdateTest::testSetBadFieldTypes() // Create a test document TestDocMan docMan; Document::UP doc(docMan.createDocument()); - CPPUNIT_ASSERT_EQUAL((document::FieldValue*)NULL, - doc->getValue(doc->getField("headerval")).get()); + CPPUNIT_ASSERT_EQUAL((document::FieldValue*)NULL, doc->getValue(doc->getField("headerval")).get()); // Assign a float value to an int field. - DocumentUpdate update(*doc->getDataType(), doc->getId()); + DocumentUpdate update(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); try { update.addUpdate(FieldUpdate(doc->getField("headerval")) .addUpdate(AssignValueUpdate(FloatFieldValue(4.00f)))); @@ -701,23 +667,19 @@ void DocumentUpdateTest::testSetBadFieldTypes() void DocumentUpdateTest::testUpdateApplyNoParams() { - // Create a test document TestDocMan docMan; Document::UP doc(docMan.createDocument()); - CPPUNIT_ASSERT_EQUAL((document::FieldValue*)NULL, - doc->getValue(doc->getField("tags")).get()); + CPPUNIT_ASSERT_EQUAL((document::FieldValue*)NULL, doc->getValue(doc->getField("tags")).get()); // Assign array field with no parameters - illegal. - DocumentUpdate update(*doc->getDataType(), doc->getId()); + DocumentUpdate update(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); try { - update.addUpdate(FieldUpdate(doc->getField("tags")) - .addUpdate(AssignValueUpdate())); + update.addUpdate(FieldUpdate(doc->getField("tags")).addUpdate(AssignValueUpdate())); CPPUNIT_FAIL("Expected exception when assign a NULL value."); } catch (std::exception& e) { ; // fprintf(stderr, "Got exception => OK: %s\n", e.what()); } - // Apply update update.applyTo(*doc); // Verify that the field was cleared in the document. @@ -727,20 +689,16 @@ DocumentUpdateTest::testUpdateApplyNoParams() void DocumentUpdateTest::testUpdateApplyNoArrayValues() { - // Create a test document TestDocMan docMan; Document::UP doc(docMan.createDocument()); const Field &field(doc->getType().getField("tags")); - CPPUNIT_ASSERT_EQUAL((document::FieldValue*) 0, - doc->getValue(field).get()); + CPPUNIT_ASSERT_EQUAL((document::FieldValue*) 0, doc->getValue(field).get()); // Assign array field with no array values = empty array - DocumentUpdate update(*doc->getDataType(), doc->getId()); + DocumentUpdate update(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); update.addUpdate(FieldUpdate(field) - .addUpdate(AssignValueUpdate( - ArrayFieldValue(field.getDataType())))); + .addUpdate(AssignValueUpdate(ArrayFieldValue(field.getDataType())))); - // Apply update update.applyTo(*doc); // Verify that the field was set in the document @@ -759,7 +717,7 @@ DocumentUpdateTest::testUpdateArrayEmptyParamValue() CPPUNIT_ASSERT_EQUAL((document::FieldValue*) 0, doc->getValue(field).get()); // Assign array field with no array values = empty array. - DocumentUpdate update(*doc->getDataType(), doc->getId()); + DocumentUpdate update(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); update.addUpdate(FieldUpdate(field).addUpdate(AssignValueUpdate(ArrayFieldValue(field.getDataType())))); update.applyTo(*doc); @@ -769,7 +727,7 @@ DocumentUpdateTest::testUpdateArrayEmptyParamValue() CPPUNIT_ASSERT_EQUAL((size_t) 0, fval1->size()); // Remove array field. - DocumentUpdate update2(*doc->getDataType(), doc->getId()); + DocumentUpdate update2(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); update2.addUpdate(FieldUpdate(field).addUpdate(ClearValueUpdate())); update2.applyTo(*doc); @@ -788,7 +746,7 @@ DocumentUpdateTest::testUpdateWeightedSetEmptyParamValue() CPPUNIT_ASSERT_EQUAL((document::FieldValue*) 0, doc->getValue(field).get()); // Assign weighted set with no items = empty set. - DocumentUpdate update(*doc->getDataType(), doc->getId()); + DocumentUpdate update(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); update.addUpdate(FieldUpdate(field).addUpdate(AssignValueUpdate(WeightedSetFieldValue(field.getDataType())))); update.applyTo(*doc); @@ -798,7 +756,7 @@ DocumentUpdateTest::testUpdateWeightedSetEmptyParamValue() CPPUNIT_ASSERT_EQUAL((size_t) 0, fval1->size()); // Remove weighted set field. - DocumentUpdate update2(*doc->getDataType(), doc->getId()); + DocumentUpdate update2(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); update2.addUpdate(FieldUpdate(field).addUpdate(ClearValueUpdate())); update2.applyTo(*doc); @@ -817,7 +775,7 @@ DocumentUpdateTest::testUpdateArrayWrongSubtype() CPPUNIT_ASSERT_EQUAL((document::FieldValue*) 0, doc->getValue(field).get()); // Assign int values to string array. - DocumentUpdate update(*doc->getDataType(), doc->getId()); + DocumentUpdate update(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); try { update.addUpdate(FieldUpdate(field) .addUpdate(AddValueUpdate(IntFieldValue(123))) @@ -842,17 +800,14 @@ DocumentUpdateTest::testUpdateWeightedSetWrongSubtype() TestDocMan docMan; Document::UP doc(docMan.createDocument()); const Field &field(doc->getType().getField("stringweightedset")); - CPPUNIT_ASSERT_EQUAL((document::FieldValue*) 0, - doc->getValue(field).get()); + CPPUNIT_ASSERT_EQUAL((document::FieldValue*) 0, doc->getValue(field).get()); // Assign int values to string array. - DocumentUpdate update(*doc->getDataType(), doc->getId()); + DocumentUpdate update(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); try { update.addUpdate(FieldUpdate(field) - .addUpdate(AddValueUpdate(IntFieldValue(123)) - .setWeight(1000)) - .addUpdate(AddValueUpdate(IntFieldValue(456)) - .setWeight(2000))); + .addUpdate(AddValueUpdate(IntFieldValue(123)).setWeight(1000)) + .addUpdate(AddValueUpdate(IntFieldValue(456)).setWeight(2000))); CPPUNIT_FAIL("Expected exception when adding wrong type."); } catch (std::exception& e) { ; // fprintf(stderr, "Got exception => OK: %s\n", e.what()); @@ -879,79 +834,61 @@ DocumentUpdateTest::testMapValueUpdate() doc->setValue(field1, wsval1); doc->setValue(field2, wsval2); - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(field1) - .addUpdate(MapValueUpdate( - StringFieldValue("banana"), - ArithmeticValueUpdate(ArithmeticValueUpdate::Add, 1.0) - ))) + .addUpdate(MapValueUpdate(StringFieldValue("banana"), + ArithmeticValueUpdate(ArithmeticValueUpdate::Add, 1.0)))) .applyTo(*doc); std::unique_ptr<WeightedSetFieldValue> fv1 = doc->getAs<WeightedSetFieldValue>(field1); CPPUNIT_ASSERT(fv1->size() == 0); - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(field2) - .addUpdate(MapValueUpdate( - StringFieldValue("banana"), - ArithmeticValueUpdate(ArithmeticValueUpdate::Add, 1.0) - ))) + .addUpdate(MapValueUpdate(StringFieldValue("banana"), + ArithmeticValueUpdate(ArithmeticValueUpdate::Add, 1.0)))) .applyTo(*doc); - std::unique_ptr<WeightedSetFieldValue> fv2 = - doc->getAs<WeightedSetFieldValue>(field2); + auto fv2 = doc->getAs<WeightedSetFieldValue>(field2); CPPUNIT_ASSERT(fv2->size() == 1); CPPUNIT_ASSERT(fv1->find(StringFieldValue("apple")) == fv1->end()); - DocumentUpdate(*doc->getDataType(), doc->getId()) - .addUpdate(FieldUpdate(field1) - .addUpdate(ClearValueUpdate())) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) + .addUpdate(FieldUpdate(field1).addUpdate(ClearValueUpdate())) .applyTo(*doc); - DocumentUpdate(*doc->getDataType(), doc->getId()) - .addUpdate(FieldUpdate(field1) - .addUpdate(AddValueUpdate(StringFieldValue("apple")) - .setWeight(1))) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) + .addUpdate(FieldUpdate(field1).addUpdate(AddValueUpdate(StringFieldValue("apple")).setWeight(1))) .applyTo(*doc); - std::unique_ptr<WeightedSetFieldValue> - fval3(doc->getAs<WeightedSetFieldValue>(field1)); + auto fval3(doc->getAs<WeightedSetFieldValue>(field1)); CPPUNIT_ASSERT(fval3->find(StringFieldValue("apple")) != fval3->end()); CPPUNIT_ASSERT_EQUAL(1, fval3->get(StringFieldValue("apple"))); - DocumentUpdate(*doc->getDataType(), doc->getId()) - .addUpdate(FieldUpdate(field2) - .addUpdate(AddValueUpdate(StringFieldValue("apple")) - .setWeight(1))) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) + .addUpdate(FieldUpdate(field2).addUpdate(AddValueUpdate(StringFieldValue("apple")).setWeight(1))) .applyTo(*doc); - std::unique_ptr<WeightedSetFieldValue> - fval3b(doc->getAs<WeightedSetFieldValue>(field2)); + auto fval3b(doc->getAs<WeightedSetFieldValue>(field2)); CPPUNIT_ASSERT(fval3b->find(StringFieldValue("apple")) != fval3b->end()); CPPUNIT_ASSERT_EQUAL(1, fval3b->get(StringFieldValue("apple"))); - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(field1) - .addUpdate(MapValueUpdate( - StringFieldValue("apple"), - ArithmeticValueUpdate(ArithmeticValueUpdate::Sub, 1.0) - ))) + .addUpdate(MapValueUpdate(StringFieldValue("apple"), + ArithmeticValueUpdate(ArithmeticValueUpdate::Sub, 1.0)))) .applyTo(*doc); - std::unique_ptr<WeightedSetFieldValue> fv3 = - doc->getAs<WeightedSetFieldValue>(field1); + auto fv3 = doc->getAs<WeightedSetFieldValue>(field1); CPPUNIT_ASSERT(fv3->find(StringFieldValue("apple")) != fv3->end()); CPPUNIT_ASSERT_EQUAL(0, fv3->get(StringFieldValue("apple"))); - DocumentUpdate(*doc->getDataType(), doc->getId()) + DocumentUpdate(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()) .addUpdate(FieldUpdate(field2) - .addUpdate(MapValueUpdate( - StringFieldValue("apple"), - ArithmeticValueUpdate(ArithmeticValueUpdate::Sub, 1.0) - ))) + .addUpdate(MapValueUpdate(StringFieldValue("apple"), + ArithmeticValueUpdate(ArithmeticValueUpdate::Sub, 1.0)))) .applyTo(*doc); - std::unique_ptr<WeightedSetFieldValue> fv4 = - doc->getAs<WeightedSetFieldValue>(field2); + auto fv4 = doc->getAs<WeightedSetFieldValue>(field2); CPPUNIT_ASSERT(fv4->find(StringFieldValue("apple")) == fv4->end()); } @@ -965,9 +902,8 @@ DocumentUpdateTest::testTensorAssignUpdate() Document updated(*doc); FieldValue::UP new_value(createTensorFieldValue()); testValueUpdate(AssignValueUpdate(*new_value), *DataType::TENSOR); - DocumentUpdate upd(*doc->getDataType(), doc->getId()); - upd.addUpdate(FieldUpdate(upd.getType().getField("tensor")). - addUpdate(AssignValueUpdate(*new_value))); + DocumentUpdate upd(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); + upd.addUpdate(FieldUpdate(upd.getType().getField("tensor")).addUpdate(AssignValueUpdate(*new_value))); upd.applyTo(updated); FieldValue::UP fval(updated.getValue("tensor")); CPPUNIT_ASSERT(fval); @@ -983,9 +919,8 @@ DocumentUpdateTest::testTensorClearUpdate() Document updated(*doc); updated.setValue(updated.getField("tensor"), *createTensorFieldValue()); CPPUNIT_ASSERT(*doc != updated); - DocumentUpdate upd(*doc->getDataType(), doc->getId()); - upd.addUpdate(FieldUpdate(upd.getType().getField("tensor")). - addUpdate(ClearValueUpdate())); + DocumentUpdate upd(docMan.getTypeRepo(), *doc->getDataType(), doc->getId()); + upd.addUpdate(FieldUpdate(upd.getType().getField("tensor")).addUpdate(ClearValueUpdate())); upd.applyTo(updated); CPPUNIT_ASSERT(!updated.getValue("tensor")); CPPUNIT_ASSERT(*doc == updated); @@ -1036,12 +971,11 @@ struct CreateIfNonExistentFixture CreateIfNonExistentFixture(); }; -CreateIfNonExistentFixture::~CreateIfNonExistentFixture() {} +CreateIfNonExistentFixture::~CreateIfNonExistentFixture() = default; CreateIfNonExistentFixture::CreateIfNonExistentFixture() : docMan(), document(docMan.createDocument()), - update(new DocumentUpdate(*document->getDataType(), - document->getId())) + update(new DocumentUpdate(docMan.getTypeRepo(), *document->getDataType(), document->getId())) { update->addUpdate(FieldUpdate(document->getField("headerval")) .addUpdate(AssignValueUpdate(IntFieldValue(1)))); @@ -1069,7 +1003,8 @@ DocumentUpdateTest::testThatCreateIfNonExistentFlagIsSerializedAndDeserialized() ByteBuffer::UP buf(serialize42(*f.update)); buf->flip(); - DocumentUpdate::UP deserialized = DocumentUpdate::create42(f.docMan.getTypeRepo(), *buf); + nbostream is(buf->getBufferAtPos(), buf->getRemaining()); + auto deserialized = DocumentUpdate::create42(f.docMan.getTypeRepo(), is); CPPUNIT_ASSERT_EQUAL(*f.update, *deserialized); CPPUNIT_ASSERT(deserialized->getCreateIfNonExistent()); } @@ -1089,7 +1024,7 @@ ArrayUpdateFixture::ArrayUpdateFixture() doc(doc_man.createDocument()), array_field(doc->getType().getField("tags")) // of type array<string> { - update = std::make_unique<DocumentUpdate>(*doc->getDataType(), doc->getId()); + update = std::make_unique<DocumentUpdate>(doc_man.getTypeRepo(), *doc->getDataType(), doc->getId()); update->addUpdate(FieldUpdate(array_field) .addUpdate(MapValueUpdate(IntFieldValue(1), AssignValueUpdate(StringFieldValue("bar"))))); diff --git a/document/src/tests/fieldpathupdatetestcase.cpp b/document/src/tests/fieldpathupdatetestcase.cpp index b240f322e4b..80a63a86b92 100644 --- a/document/src/tests/fieldpathupdatetestcase.cpp +++ b/document/src/tests/fieldpathupdatetestcase.cpp @@ -371,7 +371,7 @@ FieldPathUpdateTestCase::testRemoveField() doc->setValue("strfoo", StringFieldValue("cocacola")); CPPUNIT_ASSERT_EQUAL(vespalib::string("cocacola"), doc->getValue("strfoo")->getAsString()); //doc->print(std::cerr, true, ""); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new RemoveFieldPathUpdate("strfoo"))); docUp.applyTo(*doc); CPPUNIT_ASSERT(doc->hasValue("strfoo") == false); @@ -392,7 +392,7 @@ FieldPathUpdateTestCase::testApplyRemoveMultiList() } CPPUNIT_ASSERT(doc->hasValue("strarray")); //doc->print(std::cerr, true, ""); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new RemoveFieldPathUpdate("strarray[$x]", "foobar.strarray[$x] == \"remove val 1\""))); docUp.applyTo(*doc); @@ -417,7 +417,7 @@ FieldPathUpdateTestCase::testApplyRemoveEntireListField() doc->setValue("strarray", strArray); } //doc->print(std::cerr, true, ""); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new RemoveFieldPathUpdate("strarray", ""))); docUp.applyTo(*doc); CPPUNIT_ASSERT(!doc->hasValue("strarray")); @@ -436,7 +436,7 @@ FieldPathUpdateTestCase::testApplyRemoveMultiWset() } CPPUNIT_ASSERT(doc->hasValue("strwset")); //doc->print(std::cerr, true, ""); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new RemoveFieldPathUpdate("strwset{remove val 1}"))); docUp.applyTo(*doc); { @@ -452,14 +452,14 @@ FieldPathUpdateTestCase::testApplyAssignSingle() Document::UP doc(new Document(_foobar_type, DocumentId("doc:drekka:karsk"))); CPPUNIT_ASSERT(doc->hasValue("strfoo") == false); // Test assignment of non-existing - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*doc->getDataType(), "strfoo", std::string(), StringFieldValue("himert")))); docUp.applyTo(*doc); CPPUNIT_ASSERT(doc->hasValue("strfoo")); CPPUNIT_ASSERT_EQUAL(vespalib::string("himert"), doc->getValue("strfoo")->getAsString()); // Test overwriting existing - DocumentUpdate docUp2(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp2(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp2.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*doc->getDataType(), "strfoo", std::string(), StringFieldValue("wunderbaum")))); docUp2.applyTo(*doc); @@ -472,7 +472,7 @@ FieldPathUpdateTestCase::testApplyAssignMath() Document::UP doc(new Document(_foobar_type, DocumentId("doc:bat:man"))); doc->setValue("num", IntFieldValue(34)); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new AssignFieldPathUpdate("num", "", "($value * 2) / $value"))); docUp.applyTo(*doc); CPPUNIT_ASSERT_EQUAL(static_cast<const FieldValue&>(IntFieldValue(2)), *doc->getValue("num")); @@ -484,7 +484,7 @@ FieldPathUpdateTestCase::testApplyAssignMathByteToZero() Document::UP doc(new Document(_foobar_type, DocumentId("doc:bat:man"))); doc->setValue("byteval", ByteFieldValue(3)); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new AssignFieldPathUpdate("byteval", "", "$value - 3"))); docUp.applyTo(*doc); CPPUNIT_ASSERT_EQUAL(static_cast<const FieldValue&>(ByteFieldValue(0)), *doc->getValue("byteval")); @@ -497,7 +497,7 @@ FieldPathUpdateTestCase::testApplyAssignMathNotModifiedOnUnderflow() Document::UP doc(new Document(_foobar_type, DocumentId("doc:bat:man"))); doc->setValue("byteval", ByteFieldValue(low_value)); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new AssignFieldPathUpdate("byteval", "", "$value - 4"))); docUp.applyTo(*doc); // Over/underflow will happen. You must have control of your data types. @@ -510,7 +510,7 @@ FieldPathUpdateTestCase::testApplyAssignMathNotModifiedOnOverflow() Document::UP doc(new Document(_foobar_type, DocumentId("doc:bat:man"))); doc->setValue("byteval", ByteFieldValue(127)); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new AssignFieldPathUpdate("byteval", "", "$value + 200"))); docUp.applyTo(*doc); // Over/underflow will happen. You must have control of your data types. @@ -524,7 +524,7 @@ FieldPathUpdateTestCase::testApplyAssignMathDivZero() CPPUNIT_ASSERT(doc->hasValue("num") == false); doc->setValue("num", IntFieldValue(10)); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new AssignFieldPathUpdate("num", "", "$value / ($value - 10)"))); docUp.applyTo(*doc); CPPUNIT_ASSERT_EQUAL(static_cast<const FieldValue&>(IntFieldValue(10)), *doc->getValue("num")); @@ -538,7 +538,7 @@ FieldPathUpdateTestCase::testApplyAssignFieldNotExistingInExpression() CPPUNIT_ASSERT(doc->hasValue("num") == false); doc->setValue("num", IntFieldValue(10)); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new AssignFieldPathUpdate("num", "", "foobar.num2 + $value"))); docUp.applyTo(*doc); CPPUNIT_ASSERT_EQUAL(static_cast<const FieldValue&>(IntFieldValue(10)), *doc->getValue("num")); @@ -550,7 +550,7 @@ FieldPathUpdateTestCase::testApplyAssignFieldNotExistingInPath() Document::UP doc(new Document(_foobar_type, DocumentId("doc:bat:man"))); doc->setRepo(*_repo); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); try { docUp.addFieldPathUpdate(FieldPathUpdate::CP(new AssignFieldPathUpdate("nosuchnum", "", "foobar.num + $value"))); docUp.applyTo(*doc); @@ -565,7 +565,7 @@ FieldPathUpdateTestCase::testApplyAssignTargetNotExisting() Document::UP doc(new Document(_foobar_type, DocumentId("doc:bat:man"))); CPPUNIT_ASSERT(doc->hasValue("num") == false); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new AssignFieldPathUpdate("num", "", "$value + 5"))); docUp.applyTo(*doc); CPPUNIT_ASSERT_EQUAL(static_cast<const FieldValue&>(IntFieldValue(5)), *doc->getValue("num")); @@ -582,7 +582,7 @@ FieldPathUpdateTestCase::testAssignSimpleMapValueWithVariable() mfv.put(StringFieldValue("baz"), StringFieldValue("bananas")); doc->setValue("strmap", mfv); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); // Select on value, not key docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*doc->getDataType(), @@ -608,7 +608,7 @@ FieldPathUpdateTestCase::testApplyAssignMathRemoveIfZero() doc->setValue("num", IntFieldValue(34)); CPPUNIT_ASSERT(doc->hasValue("num") == true); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); FieldPathUpdate::CP up1(new AssignFieldPathUpdate("num", "", "($value * 2) / $value - 2")); static_cast<AssignFieldPathUpdate&>(*up1).setRemoveIfZero(true); docUp.addFieldPathUpdate(up1); @@ -635,7 +635,7 @@ FieldPathUpdateTestCase::testApplyAssignMultiList() updateArray.add(StringFieldValue("assigned val 0")); updateArray.add(StringFieldValue("assigned val 1")); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*doc->getDataType(), "strarray", std::string(), updateArray))); docUp.applyTo(*doc); @@ -667,7 +667,7 @@ FieldPathUpdateTestCase::testApplyAssignMultiWset() assignWset.add(StringFieldValue("assigned val 0"), 5); assignWset.add(StringFieldValue("assigned val 1"), 10); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*doc->getDataType(), "strwset", std::string(), assignWset))); //doc->print(std::cerr, true, ""); @@ -696,7 +696,7 @@ FieldPathUpdateTestCase::testAssignWsetRemoveIfZero() } { - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); IntFieldValue zeroWeight(0); FieldPathUpdate::CP assignUpdate( new AssignFieldPathUpdate(*doc->getDataType(), "strwset{you say goodbye}", std::string(), zeroWeight)); @@ -724,7 +724,7 @@ FieldPathUpdateTestCase::testApplyAddMultiList() adds.add(StringFieldValue("a festivus for the rest of us")); adds.add(StringFieldValue("george is getting upset!")); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AddFieldPathUpdate(*doc->getDataType(), "strarray", std::string(), adds))); //doc->print(std::cerr, true, ""); @@ -747,7 +747,7 @@ FieldPathUpdateTestCase::testAddAndAssignList() CPPUNIT_ASSERT(doc->hasValue("strarray")); } - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*doc->getDataType(), "strarray[1]", std::string(), StringFieldValue("assigned val 1")))); @@ -829,7 +829,7 @@ FieldPathUpdateTestCase::testAssignMap() Keys k; Fixture f(_foobar_type, k); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*f.doc->getDataType(), "structmap{" + k.key2 + "}", std::string(), f.fv4))); docUp.applyTo(*f.doc); @@ -850,7 +850,7 @@ FieldPathUpdateTestCase::testAssignMapStruct() Keys k; Fixture f(_foobar_type, k); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*f.doc->getDataType(), "structmap{" + k.key2 + "}.rating", std::string(), IntFieldValue(48)))); @@ -872,7 +872,7 @@ FieldPathUpdateTestCase::testAssignMapStructVariable() Keys k; Fixture f(_foobar_type, k); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*f.doc->getDataType(), "structmap{$x}.rating", "foobar.structmap{$x}.title == \"farnsworth\"", IntFieldValue(48)))); @@ -899,7 +899,7 @@ FieldPathUpdateTestCase::testAssignMapNoExist() fv1.setValue("title", StringFieldValue("fry")); fv1.setValue("rating", IntFieldValue(30)); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*doc->getDataType(), "structmap{foo}", std::string(), fv1))); //doc->print(std::cerr, true, ""); @@ -922,7 +922,7 @@ FieldPathUpdateTestCase::testAssignMapNoExistNoCreate() fv1.setValue("title", StringFieldValue("fry")); fv1.setValue("rating", IntFieldValue(30)); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); FieldPathUpdate::CP assignUpdate( new AssignFieldPathUpdate(*doc->getDataType(), "structmap{foo}", std::string(), fv1)); static_cast<AssignFieldPathUpdate&>(*assignUpdate).setCreateMissingPath(false); @@ -944,7 +944,7 @@ FieldPathUpdateTestCase::testQuotedStringKey() const char field_path[] = "structmap{\"here is a \\\"fancy\\\" 'map' :-} key :-{\"}"; Fixture f(_foobar_type, k); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP( new AssignFieldPathUpdate(*f.doc->getDataType(), field_path, std::string(), f.fv4))); docUp.applyTo(*f.doc); @@ -970,8 +970,8 @@ FieldPathUpdateTestCase::testEqualityComparison() fv4.setValue("rating", IntFieldValue(95)); { - DocumentUpdate docUp1(_foobar_type, DocumentId("doc:barbar:foofoo")); - DocumentUpdate docUp2(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp1(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp2(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); CPPUNIT_ASSERT(docUp1 == docUp2); FieldPathUpdate::CP assignUp1(new AssignFieldPathUpdate(*doc->getDataType(), @@ -982,8 +982,8 @@ FieldPathUpdateTestCase::testEqualityComparison() CPPUNIT_ASSERT(docUp1 == docUp2); } { - DocumentUpdate docUp1(_foobar_type, DocumentId("doc:barbar:foofoo")); - DocumentUpdate docUp2(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp1(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp2(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); // where-clause diff FieldPathUpdate::CP assignUp1(new AssignFieldPathUpdate(*doc->getDataType(), "structmap{here be dragons}", std::string(), fv4)); @@ -994,8 +994,8 @@ FieldPathUpdateTestCase::testEqualityComparison() CPPUNIT_ASSERT(docUp1 != docUp2); } { - DocumentUpdate docUp1(_foobar_type, DocumentId("doc:barbar:foofoo")); - DocumentUpdate docUp2(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp1(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp2(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); // fieldpath diff FieldPathUpdate::CP assignUp1(new AssignFieldPathUpdate(*doc->getDataType(), "structmap{here be dragons}", std::string(), fv4)); @@ -1020,7 +1020,7 @@ FieldPathUpdateTestCase::testAffectsDocumentBody() // structmap is body field { - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); FieldPathUpdate::CP update1(new AssignFieldPathUpdate(*doc->getDataType(), "structmap{janitor}", std::string(), fv4)); @@ -1030,7 +1030,7 @@ FieldPathUpdateTestCase::testAffectsDocumentBody() // strfoo is header field { - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); FieldPathUpdate::CP update1(new AssignFieldPathUpdate(*doc->getDataType(), "strfoo", std::string(), StringFieldValue("helloworld"))); static_cast<AssignFieldPathUpdate&>(*update1).setCreateMissingPath(true); @@ -1045,7 +1045,7 @@ FieldPathUpdateTestCase::testIncompatibleDataTypeFails() Document::UP doc(new Document(_foobar_type, DocumentId("doc:things:stuff"))); MapFieldValue mfv(doc->getType().getField("structmap").getDataType()); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); try { FieldPathUpdate::CP update1(new AssignFieldPathUpdate(*doc->getDataType(), "structmap{foo}", @@ -1066,7 +1066,7 @@ FieldPathUpdateTestCase::testSerializeAssign() val.setValue("title", StringFieldValue("cool frog")); val.setValue("rating", IntFieldValue(100)); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); FieldPathUpdate::CP update1(new AssignFieldPathUpdate(*doc->getDataType(), "structmap{ribbit}", "true", val)); static_cast<AssignFieldPathUpdate&>(*update1).setCreateMissingPath(true); @@ -1086,7 +1086,7 @@ FieldPathUpdateTestCase::testSerializeAdd() adds.add(StringFieldValue("a festivus for the rest of us")); adds.add(StringFieldValue("george is getting upset!")); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); FieldPathUpdate::CP update1(new AddFieldPathUpdate(*doc->getDataType(), "strarray", std::string(), adds)); docUp.addFieldPathUpdate(update1); @@ -1100,7 +1100,7 @@ FieldPathUpdateTestCase::testSerializeRemove() Document::UP doc(new Document(_foobar_type, DocumentId("doc:weloveto:serializestuff"))); MapFieldValue mfv(doc->getType().getField("structmap").getDataType()); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); FieldPathUpdate::CP update1(new RemoveFieldPathUpdate("structmap{ribbit}", std::string())); docUp.addFieldPathUpdate(update1); @@ -1115,7 +1115,7 @@ FieldPathUpdateTestCase::testSerializeAssignMath() CPPUNIT_ASSERT(doc->hasValue("num") == false); doc->setValue("num", IntFieldValue(34)); - DocumentUpdate docUp(_foobar_type, DocumentId("doc:barbar:foofoo")); + DocumentUpdate docUp(*_repo, _foobar_type, DocumentId("doc:barbar:foofoo")); docUp.addFieldPathUpdate(FieldPathUpdate::CP(new AssignFieldPathUpdate("num", "", "($value * 2) / $value"))); testSerialize(*_repo, docUp); } @@ -1124,7 +1124,7 @@ DocumentUpdate::UP FieldPathUpdateTestCase::createDocumentUpdateForSerialization(const DocumentTypeRepo& repo) { const DocumentType *docType(repo.getDocumentType("serializetest")); - DocumentUpdate::UP docUp(new DocumentUpdate(*docType, DocumentId("doc:serialization:xlanguage"))); + DocumentUpdate::UP docUp(new DocumentUpdate(repo, *docType, DocumentId("doc:serialization:xlanguage"))); FieldPathUpdate::CP assign(new AssignFieldPathUpdate("intfield", "", "3")); static_cast<AssignFieldPathUpdate&>(*assign).setRemoveIfZero(true); diff --git a/document/src/tests/testxml.cpp b/document/src/tests/testxml.cpp index 4cc1306ff45..09c2ef86279 100644 --- a/document/src/tests/testxml.cpp +++ b/document/src/tests/testxml.cpp @@ -73,7 +73,7 @@ createTestDocumentUpdate(const DocumentTypeRepo& repo) const DocumentType* type(repo.getDocumentType("testdoc")); DocumentId id("doc:crawler/http://www.ntnu.no/"); - DocumentUpdate::UP up(new DocumentUpdate(*type, id)); + DocumentUpdate::UP up(new DocumentUpdate(repo, *type, id)); up->addUpdate(FieldUpdate(type->getField("intattr")) .addUpdate(AssignValueUpdate(IntFieldValue(7)))); up->addUpdate(FieldUpdate(type->getField("stringattr")) diff --git a/document/src/vespa/document/base/forcelink.cpp b/document/src/vespa/document/base/forcelink.cpp index 8f683e40059..bc0097b68f4 100644 --- a/document/src/vespa/document/base/forcelink.cpp +++ b/document/src/vespa/document/base/forcelink.cpp @@ -13,7 +13,7 @@ ForceLink::ForceLink(void) if (time(NULL) == 0) { DocumentType type("foo", 1); Document document(type, DocumentId("doc:ns:bar")); - DocumentUpdate documentUpdate(type, DocumentId("doc:ns:bar")); + DocumentUpdate documentUpdate; MapValueUpdate mapValueUpdate(IntFieldValue(3), ClearValueUpdate()); AddValueUpdate addValueUpdate(IntFieldValue(3)); RemoveValueUpdate removeValueUpdate(IntFieldValue(3)); diff --git a/document/src/vespa/document/serialization/vespadocumentserializer.cpp b/document/src/vespa/document/serialization/vespadocumentserializer.cpp index 1a628ea2618..dac5ca4458b 100644 --- a/document/src/vespa/document/serialization/vespadocumentserializer.cpp +++ b/document/src/vespa/document/serialization/vespadocumentserializer.cpp @@ -439,17 +439,19 @@ void VespaDocumentSerializer::write42(const DocumentUpdate &value) void VespaDocumentSerializer::writeHEAD(const DocumentUpdate &value) { + if (!value._needHardReserialize) { + _stream.write(value._backing.peek(), value._backing.size()); + return; + } write(value.getId()); _stream.write(value.getType().getName().c_str(), value.getType().getName().size() + 1); _stream << static_cast<uint16_t>(0); - const DocumentUpdate::FieldUpdateV & updates(value.getUpdates()); - _stream << static_cast<uint32_t>(updates.size()); - for (const auto & update : updates) { + _stream << static_cast<uint32_t>(value._updates.size()); + for (const auto & update : value._updates) { write(update); } - const DocumentUpdate::FieldPathUpdateV & fieldPathUpdates(value.getFieldPathUpdates()); - _stream << static_cast<uint32_t>(value.serializeFlags(fieldPathUpdates.size())); - for (const auto & update : fieldPathUpdates) { + _stream << static_cast<uint32_t>(value.serializeFlags(value._fieldPathUpdates.size())); + for (const auto & update : value._fieldPathUpdates) { _stream << update->getSerializedType(); write(*update); } diff --git a/document/src/vespa/document/update/documentupdate.cpp b/document/src/vespa/document/update/documentupdate.cpp index 30b760a6102..7673782dba4 100644 --- a/document/src/vespa/document/update/documentupdate.cpp +++ b/document/src/vespa/document/update/documentupdate.cpp @@ -25,59 +25,43 @@ namespace document { // Declare content bits. static const unsigned char CONTENT_HASTYPE = 0x01; -DocumentUpdate::DocumentUpdate(const DataType &type, const DocumentId& id) +DocumentUpdate::DocumentUpdate(const DocumentTypeRepo & repo, const DataType &type, const DocumentId& id) : _documentId(id), _type(&type), + _repo(&repo), + _backing(), _updates(), _fieldPathUpdates(), _version(Document::getNewestSerializationVersion()), - _createIfNonExistent(false) + _createIfNonExistent(false), + _needHardReserialize(false) { if (!type.getClass().inherits(DocumentType::classId)) { - throw IllegalArgumentException("Cannot generate a document with non-document type " + type.toString() + ".", - VESPA_STRLOC); + throw IllegalArgumentException("Cannot generate a document with non-document type " + type.toString() + ".", VESPA_STRLOC); } + serializeHeader(); } -DocumentUpdate::DocumentUpdate(const DocumentTypeRepo& repo, - ByteBuffer& buffer, - SerializeVersion serializeVersion) - : _documentId("doc::"), +DocumentUpdate::DocumentUpdate() + : _documentId(), _type(DataType::DOCUMENT), + _repo(nullptr), + _backing(), _updates(), + _fieldPathUpdates(), _version(Document::getNewestSerializationVersion()), - _createIfNonExistent(false) + _createIfNonExistent(false), + _needHardReserialize(false) { - switch (serializeVersion) { - case SerializeVersion::SERIALIZE_HEAD: - deserializeHEAD(repo, buffer); - break; - case SerializeVersion::SERIALIZE_42: - deserialize42(repo, buffer); - break; - default: - throw IllegalArgumentException("bad serializeVersion provided.", VESPA_STRLOC); - } } DocumentUpdate::~DocumentUpdate() = default; - bool DocumentUpdate::operator==(const DocumentUpdate& other) const { - if (_documentId != other._documentId) return false; - if (*_type != *other._type) return false; - if (_updates.size() != other._updates.size()) return false; - for (std::size_t i = 0, n = _updates.size(); i < n; ++i) { - if (_updates[i] != other._updates[i]) return false; - } - if (_fieldPathUpdates.size() != other._fieldPathUpdates.size()) return false; - for (std::size_t i = 0, n = _fieldPathUpdates.size(); i < n; ++i) { - if (*_fieldPathUpdates[i] != *other._fieldPathUpdates[i]) return false; - } - if (_createIfNonExistent != other._createIfNonExistent) return false; - return true; + return (_backing.size() == other._backing.size()) && + (memcmp(_backing.peek(), other._backing.peek(), _backing.size()) == 0); } const DocumentType& @@ -85,22 +69,67 @@ DocumentUpdate::getType() const { return static_cast<const DocumentType &> (*_type); } +const DocumentUpdate::FieldUpdateV & +DocumentUpdate::getUpdates() const { + ensureDeserialized(); + return _updates; +} + +const DocumentUpdate::FieldPathUpdateV & +DocumentUpdate::getFieldPathUpdates() const { + ensureDeserialized(); + return _fieldPathUpdates; +} + +void +DocumentUpdate::eagerDeserialize() const { + ensureDeserialized(); +} + +void DocumentUpdate::lazyDeserialize(const DocumentTypeRepo & repo, nbostream & stream) { + size_t start(stream.rp()); + deserializeHEAD(repo, stream); + stream.rp(start); +} +void DocumentUpdate::ensureDeserialized() const { + if (_updates.empty() && _fieldPathUpdates.empty()) { + const_cast<DocumentUpdate &>(*this).lazyDeserialize(*_repo, const_cast<nbostream &>(_backing)); + } +} + DocumentUpdate& DocumentUpdate::addUpdate(const FieldUpdate& update) { + ensureDeserialized(); _updates.push_back(update); + reserialize(); return *this; } DocumentUpdate& DocumentUpdate::addFieldPathUpdate(const FieldPathUpdate::CP& update) { + ensureDeserialized(); _fieldPathUpdates.push_back(update); + reserialize(); return *this; } void -DocumentUpdate::print(std::ostream& out, bool verbose, - const std::string& indent) const +DocumentUpdate::setCreateIfNonExistent(bool value) { + ensureDeserialized(); + _createIfNonExistent = value; + reserialize(); +} + +bool +DocumentUpdate::getCreateIfNonExistent() const { + ensureDeserialized(); + return _createIfNonExistent; +} + +void +DocumentUpdate::print(std::ostream& out, bool verbose, const std::string& indent) const { + ensureDeserialized(); out << "DocumentUpdate("; if (_type) { _type->print(out, verbose, indent + " "); @@ -131,6 +160,7 @@ DocumentUpdate::print(std::ostream& out, bool verbose, void DocumentUpdate::applyTo(Document& doc) const { + ensureDeserialized(); const DocumentType& type = doc.getType(); if (_type->getName() != type.getName()) { string err = make_string("Can not apply a \"%s\" document update to a \"%s\" document.", @@ -150,6 +180,17 @@ DocumentUpdate::applyTo(Document& doc) const } void +DocumentUpdate::serializeHeader() { + string id_string = _documentId.getScheme().toString(); + _backing.write(id_string.data(), id_string.size()); + _backing << static_cast<uint8_t>(0); + _backing.write(getType().getName().c_str(), getType().getName().size() + 1); + _backing << static_cast<uint16_t>(0); + _backing << static_cast<uint32_t>(0); + _backing << static_cast<uint32_t>(0); +} + +void DocumentUpdate::serializeHEAD(nbostream &stream) const { VespaDocumentSerializer serializer(stream); @@ -165,92 +206,147 @@ DocumentUpdate::serializeFlags(int size_) const } namespace { - std::pair<const DocumentType *, DocumentId> - deserializeTypeAndId(const DocumentTypeRepo& repo, ByteBuffer& buffer) { - nbostream stream(buffer.getBufferAtPos(), buffer.getRemaining()); - DocumentId docId(stream); - buffer.incPos(stream.rp()); - - // Read content bit vector. - unsigned char content = 0x00; - buffer.getByte(content); - - // Why on earth do we have this whether we have type part? - // We need type for object to work, so just throwing exception if it's - // not there. - if((content & CONTENT_HASTYPE) == 0) { - throw IllegalStateException("Missing document type", VESPA_STRLOC); - } +std::pair<const DocumentType *, DocumentId> +deserializeTypeAndId(const DocumentTypeRepo& repo, vespalib::nbostream & stream) { + DocumentId docId(stream); + + // Read content bit vector. + unsigned char content = 0x00; + stream >> content; + + // Why on earth do we have this whether we have type part? + // We need type for object to work, so just throwing exception if it's + // not there. + if((content & CONTENT_HASTYPE) == 0) { + throw IllegalStateException("Missing document type", VESPA_STRLOC); + } - vespalib::stringref typestr = buffer.getBufferAtPos(); - buffer.incPos(typestr.length() + 1); + vespalib::stringref typestr = stream.peek(); + stream.adjustReadPos(typestr.length() + 1); - int16_t version = 0; - buffer.getShortNetwork(version); - const DocumentType *type = repo.getDocumentType(typestr); - if (!type) { - throw DocumentTypeNotFoundException(typestr, VESPA_STRLOC); - } - return std::make_pair(type, docId); + int16_t version = 0; + stream >> version; + const DocumentType *type = repo.getDocumentType(typestr); + if (!type) { + throw DocumentTypeNotFoundException(typestr, VESPA_STRLOC); } + return std::make_pair(type, docId); +} } // Deserialize the content of the given buffer into this document update. DocumentUpdate::UP -DocumentUpdate::create42(const DocumentTypeRepo& repo, ByteBuffer& buffer) +DocumentUpdate::create42(const DocumentTypeRepo& repo, vespalib::nbostream & stream) { - return std::make_unique<DocumentUpdate>(repo, buffer, SerializeVersion::SERIALIZE_42); + auto update = std::make_unique<DocumentUpdate>(); + update->init42(repo, stream); + return update; } DocumentUpdate::UP DocumentUpdate::createHEAD(const DocumentTypeRepo& repo, ByteBuffer& buffer) { - return std::make_unique<DocumentUpdate>(repo, buffer, SerializeVersion::SERIALIZE_HEAD); + vespalib::nbostream is(buffer.getBufferAtPos(), buffer.getRemaining()); + auto update = std::make_unique<DocumentUpdate>(); + update->initHEAD(repo, is); + buffer.setPos(buffer.getPos() + is.rp()); + return update; +} + +DocumentUpdate::UP +DocumentUpdate::createHEAD(const DocumentTypeRepo& repo, vespalib::nbostream stream) +{ + auto update = std::make_unique<DocumentUpdate>(); + update->initHEAD(repo, std::move(stream)); + return update; } void -DocumentUpdate::deserialize42(const DocumentTypeRepo& repo, ByteBuffer& buffer) +DocumentUpdate::init42(const DocumentTypeRepo & repo, vespalib::nbostream & stream) { - int pos = buffer.getPos(); - try{ - buffer.getShortNetwork(_version); + _repo = &repo; + deserialize42(repo, stream); + reserialize(); +} +void +DocumentUpdate::initHEAD(const DocumentTypeRepo & repo, vespalib::nbostream && stream) +{ + _repo = &repo; + _backing = std::move(stream); + size_t startPos = _backing.rp(); + deserializeHeader(repo, _backing); + _backing.rp(startPos); +} + +void +DocumentUpdate::initHEAD(const DocumentTypeRepo & repo, vespalib::nbostream & stream) +{ + size_t startPos = stream.rp(); + deserializeHEAD(repo, stream); + size_t sz = stream.rp() - startPos; + _backing = nbostream(stream.peek() - sz, sz); +} - std::pair<const DocumentType *, DocumentId> typeAndId(deserializeTypeAndId(repo, buffer)); +void +DocumentUpdate::deserialize42(const DocumentTypeRepo& repo, vespalib::nbostream & stream) +{ + size_t pos = stream.rp(); + try{ + int16_t version(0); + stream >> version; + std::pair<const DocumentType *, DocumentId> typeAndId(deserializeTypeAndId(repo, stream)); _type = typeAndId.first; _documentId = typeAndId.second; // Read field updates, if any. - if(buffer.getRemaining() > 0) { + if (! stream.empty()) { int sizeAndFlags = 0; - buffer.getIntNetwork(sizeAndFlags); + stream >> sizeAndFlags; int numUpdates = deserializeFlags(sizeAndFlags); _updates.reserve(numUpdates); + ByteBuffer buffer(stream.peek(), stream.size()); for (int i = 0; i < numUpdates; i++) { _updates.emplace_back(repo, *typeAndId.first, buffer, _version); } + stream.adjustReadPos(buffer.getPos()); } } catch (const DeserializeException &) { - buffer.setPos(pos); + stream.rp(pos); throw; } catch (const BufferOutOfBoundsException &) { - buffer.setPos(pos); + stream.rp(pos); throw; } } void -DocumentUpdate::deserializeHEAD(const DocumentTypeRepo &repo, ByteBuffer &buffer) +DocumentUpdate::deserializeHeader(const DocumentTypeRepo &repo, vespalib::nbostream & stream) +{ + assert(_updates.empty()); + assert(_fieldPathUpdates.empty()); + _documentId = DocumentId(stream); + + vespalib::stringref typestr = stream.peek(); + stream.adjustReadPos(typestr.length() + 1); + int16_t version = 0; + stream >> version; + const DocumentType *docType = repo.getDocumentType(typestr); + _type = docType; +} + +void +DocumentUpdate::deserializeHEAD(const DocumentTypeRepo &repo, vespalib::nbostream & stream) { - int pos = buffer.getPos(); + _updates.clear(); + _fieldPathUpdates.clear(); + size_t pos = stream.rp(); try { - nbostream stream(buffer.getBufferAtPos(), buffer.getRemaining()); _documentId = DocumentId(stream); - buffer.incPos(stream.rp()); - vespalib::stringref typestr = buffer.getBufferAtPos(); - buffer.incPos(typestr.length() + 1); + vespalib::stringref typestr = stream.peek(); + stream.adjustReadPos(typestr.length() + 1); int16_t version = 0; - buffer.getShortNetwork(version); + stream >> version; const DocumentType *docType = repo.getDocumentType(typestr); if (!docType) { throw DocumentTypeNotFoundException(typestr, VESPA_STRLOC); @@ -258,27 +354,31 @@ DocumentUpdate::deserializeHEAD(const DocumentTypeRepo &repo, ByteBuffer &buffer _type = docType; // Read field updates, if any. - if (buffer.getRemaining() > 0) { + if ( ! stream.empty() ) { int numUpdates = 0; - buffer.getIntNetwork(numUpdates); + stream >> numUpdates; _updates.reserve(numUpdates); + ByteBuffer buffer(stream.peek(), stream.size()); for (int i = 0; i < numUpdates; i++) { - _updates.emplace_back(repo, *docType, buffer, 8); + _updates.emplace_back(repo, *docType, buffer, _version); } + stream.adjustReadPos(buffer.getPos()); } // Read fieldpath updates, if any int sizeAndFlags = 0; - buffer.getIntNetwork(sizeAndFlags); + stream >> sizeAndFlags; int numUpdates = deserializeFlags(sizeAndFlags); _fieldPathUpdates.reserve(numUpdates); + ByteBuffer buffer(stream.peek(), stream.size()); for (int i = 0; i < numUpdates; ++i) { - _fieldPathUpdates.emplace_back(FieldPathUpdate::createInstance(repo, *_type, buffer, 8).release()); + _fieldPathUpdates.emplace_back(FieldPathUpdate::createInstance(repo, *_type, buffer, _version).release()); } + stream.adjustReadPos(buffer.getPos()); } catch (const DeserializeException &) { - buffer.setPos(pos); + stream.rp(pos); throw; } catch (const BufferOutOfBoundsException &) { - buffer.setPos(pos); + stream.rp(pos); throw; } } @@ -293,6 +393,7 @@ DocumentUpdate::deserializeFlags(int sizeAndFlags) void DocumentUpdate::printXml(XmlOutputStream& xos) const { + ensureDeserialized(); xos << XmlTag("document") << XmlAttribute("type", _type->getName()) << XmlAttribute("id", getId().toString()); @@ -304,4 +405,15 @@ DocumentUpdate::printXml(XmlOutputStream& xos) const xos << XmlEndTag(); } +void +DocumentUpdate::reserialize() +{ + nbostream stream; + VespaDocumentSerializer serializer(stream); + _needHardReserialize = true; + serializer.writeHEAD(*this); + _backing = std::move(stream); + _needHardReserialize = false; +} + } diff --git a/document/src/vespa/document/update/documentupdate.h b/document/src/vespa/document/update/documentupdate.h index c6250fb6b75..f791dceb496 100644 --- a/document/src/vespa/document/update/documentupdate.h +++ b/document/src/vespa/document/update/documentupdate.h @@ -41,16 +41,6 @@ class VespaDocumentSerializer; */ class DocumentUpdate final : public Printable, public XmlSerializable { -private: - /** - * Enum class containing the legal serialization version for - * document updates. This version is not encoded in the serialized - * document update. - */ - enum class SerializeVersion { - SERIALIZE_42, // old style format, before vespa 5.0 - SERIALIZE_HEAD // new style format, since vespa 5.0 - }; public: typedef std::unique_ptr<DocumentUpdate> UP; typedef std::shared_ptr<DocumentUpdate> SP; @@ -60,12 +50,13 @@ public: /** * Create old style document update, no support for field path updates. */ - static DocumentUpdate::UP create42(const DocumentTypeRepo&, ByteBuffer&); + static DocumentUpdate::UP create42(const DocumentTypeRepo & repo, vespalib::nbostream & stream); /** * Create new style document update, possibly with field path updates. */ - static DocumentUpdate::UP createHEAD(const DocumentTypeRepo&, ByteBuffer&); + static DocumentUpdate::UP createHEAD(const DocumentTypeRepo & repo, vespalib::nbostream stream); + static DocumentUpdate::UP createHEAD(const DocumentTypeRepo & repo, ByteBuffer & buffer); /** * Create a document update from a byte buffer containing a serialized @@ -75,7 +66,7 @@ public: * @param buffer The buffer containing the serialized document update * @param serializeVersion Selector between serialization formats. */ - DocumentUpdate(const DocumentTypeRepo &repo, ByteBuffer &buffer, SerializeVersion serializeVersion); + DocumentUpdate(); /** * The document type is not strictly needed, as we know this at applyTo() * time, but search does not use applyTo() code to do the update, and don't @@ -86,7 +77,7 @@ public: * @param type The document type that this update is applicable for. * @param id The identifier of the document that this update is created for. */ - DocumentUpdate(const DataType &type, const DocumentId& id); + DocumentUpdate(const DocumentTypeRepo & repo, const DataType &type, const DocumentId& id); DocumentUpdate(const DocumentUpdate &) = delete; DocumentUpdate & operator = (const DocumentUpdate &) = delete; @@ -104,63 +95,61 @@ public: * type as this. */ void applyTo(Document& doc) const; - - /** - * Add a field update to this document update. - * @return A reference to this. - */ - DocumentUpdate& addUpdate(const FieldUpdate& update); - /** - * Add a fieldpath update to this document update. - * @return A reference to this. - */ + DocumentUpdate& addUpdate(const FieldUpdate& update); DocumentUpdate& addFieldPathUpdate(const FieldPathUpdate::CP& update); /** @return The list of updates. */ - const FieldUpdateV & getUpdates() const { return _updates; } + const FieldUpdateV & getUpdates() const; /** @return The list of fieldpath updates. */ - const FieldPathUpdateV & getFieldPathUpdates() const { return _fieldPathUpdates; } + const FieldPathUpdateV & getFieldPathUpdates() const; + + void eagerDeserialize() const; /** @return The type of document this update is for. */ const DocumentType& getType() const; - void print(std::ostream& out, bool verbose, const std::string& indent) const override; - void serializeHEAD(vespalib::nbostream &stream) const; - void printXml(XmlOutputStream&) const override; /** * Sets whether this update should create the document it updates if that document does not exist. * In this case an empty document is created before the update is applied. */ - void setCreateIfNonExistent(bool value) { - _createIfNonExistent = value; - } + void setCreateIfNonExistent(bool value); /** * Gets whether this update should create the document it updates if that document does not exist. */ - bool getCreateIfNonExistent() const { - return _createIfNonExistent; - } + bool getCreateIfNonExistent() const; int serializeFlags(int size_) const; int16_t getVersion() const { return _version; } private: - DocumentId _documentId; // The ID of the document to update. - const DataType *_type; // The type of document this update is for. - FieldUpdateV _updates; // The list of field updates. - FieldPathUpdateV _fieldPathUpdates; - int16_t _version; // Serialization version - bool _createIfNonExistent; + DocumentId _documentId; // The ID of the document to update. + const DataType *_type; // The type of document this update is for. + const DocumentTypeRepo *_repo; + vespalib::nbostream _backing; + FieldUpdateV _updates; // The list of field updates. + FieldPathUpdateV _fieldPathUpdates; + const int16_t _version; // Serialization version + bool _createIfNonExistent; + bool _needHardReserialize; int deserializeFlags(int sizeAndFlags); - void deserialize42(const DocumentTypeRepo&, ByteBuffer&); - void deserializeHEAD(const DocumentTypeRepo&, ByteBuffer&); + void init42(const DocumentTypeRepo & repo, vespalib::nbostream & stream); + void initHEAD(const DocumentTypeRepo & repo, vespalib::nbostream && stream); + void initHEAD(const DocumentTypeRepo & repo, vespalib::nbostream & stream); + void deserialize42(const DocumentTypeRepo & repo, vespalib::nbostream & stream); + void deserializeHEAD(const DocumentTypeRepo & repo, vespalib::nbostream & stream); + void lazyDeserialize(const DocumentTypeRepo & repo, vespalib::nbostream & stream); + void ensureDeserialized() const; + void serializeHeader(); + void reserialize(); + void deserializeHeader(const DocumentTypeRepo & repo, vespalib::nbostream & stream); + friend VespaDocumentSerializer; }; } // document |