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 | |
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.
32 files changed, 450 insertions, 428 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 diff --git a/documentapi/src/tests/messagebus/messagebus_test.cpp b/documentapi/src/tests/messagebus/messagebus_test.cpp index cd2820d8c05..dff3f3f1bac 100644 --- a/documentapi/src/tests/messagebus/messagebus_test.cpp +++ b/documentapi/src/tests/messagebus/messagebus_test.cpp @@ -59,7 +59,7 @@ void Test::testMessage() { // Test one update. UpdateDocumentMessage upd1( document::DocumentUpdate::SP( - new document::DocumentUpdate(*testdoc_type, + new document::DocumentUpdate(*_repo, *testdoc_type, document::DocumentId(document::DocIdString( "testdoc", "testme1"))))); @@ -80,7 +80,7 @@ void Test::testMessage() { // Compare to another. UpdateDocumentMessage upd2( document::DocumentUpdate::SP( - new document::DocumentUpdate(*testdoc_type, + new document::DocumentUpdate(*_repo, *testdoc_type, document::DocumentId(document::DocIdString( "testdoc", "testme2"))))); EXPECT_TRUE(!(upd1.getDocumentUpdate().getId() == upd2.getDocumentUpdate().getId())); diff --git a/documentapi/src/tests/messages/messages50test.cpp b/documentapi/src/tests/messages/messages50test.cpp index 48728ff6057..6705277d5c3 100644 --- a/documentapi/src/tests/messages/messages50test.cpp +++ b/documentapi/src/tests/messages/messages50test.cpp @@ -672,8 +672,7 @@ Messages50Test::testUpdateDocumentMessage() { const DocumentTypeRepo &repo = getTypeRepo(); const document::DocumentType &docType = *repo.getDocumentType("testdoc"); - document::DocumentUpdate::SP - upd(new document::DocumentUpdate(docType, document::DocumentId("doc:scheme:"))); + auto upd(std::make_shared<document::DocumentUpdate>(repo, docType, document::DocumentId("doc:scheme:"))); upd->addFieldPathUpdate(document::FieldPathUpdate::CP( new document::RemoveFieldPathUpdate("intfield", "testdoc.intfield > 0"))); UpdateDocumentMessage msg(upd); @@ -682,7 +681,7 @@ Messages50Test::testUpdateDocumentMessage() EXPECT_EQUAL(MESSAGE_BASE_LENGTH + 89u, serialize("UpdateDocumentMessage", msg)); for (uint32_t lang = 0; lang < NUM_LANGUAGES; ++lang) { mbus::Routable::UP obj = deserialize("UpdateDocumentMessage", DocumentProtocol::MESSAGE_UPDATEDOCUMENT, lang); - if (EXPECT_TRUE(obj.get() != NULL)) { + if (EXPECT_TRUE(obj.get() != nullptr)) { UpdateDocumentMessage &ref = static_cast<UpdateDocumentMessage&>(*obj); EXPECT_EQUAL(*upd, ref.getDocumentUpdate()); EXPECT_EQUAL(666u, ref.getOldTimestamp()); @@ -703,21 +702,21 @@ Messages50Test::testBatchDocumentUpdateMessage() { document::DocumentUpdate::SP upd; - upd.reset(new document::DocumentUpdate(docType, document::DocumentId("userdoc:footype:1234:foo"))); + upd.reset(new document::DocumentUpdate(repo, docType, document::DocumentId("userdoc:footype:1234:foo"))); upd->addFieldPathUpdate(document::FieldPathUpdate::CP( new document::RemoveFieldPathUpdate("intfield", "testdoc.intfield > 0"))); msg.addUpdate(upd); } { document::DocumentUpdate::SP upd; - upd.reset(new document::DocumentUpdate(docType, document::DocumentId("orderdoc(32,17):footype:1234:123456789:foo"))); + upd.reset(new document::DocumentUpdate(repo, docType, document::DocumentId("orderdoc(32,17):footype:1234:123456789:foo"))); upd->addFieldPathUpdate(document::FieldPathUpdate::CP( new document::RemoveFieldPathUpdate("intfield", "testdoc.intfield > 0"))); msg.addUpdate(upd); } try { document::DocumentUpdate::SP upd; - upd.reset(new document::DocumentUpdate(docType, document::DocumentId("userdoc:footype:5678:foo"))); + upd.reset(new document::DocumentUpdate(repo, docType, document::DocumentId("userdoc:footype:5678:foo"))); upd->addFieldPathUpdate(document::FieldPathUpdate::CP( new document::RemoveFieldPathUpdate("intfield", "testdoc.intfield > 0"))); msg.addUpdate(upd); @@ -726,7 +725,7 @@ Messages50Test::testBatchDocumentUpdateMessage() } try { document::DocumentUpdate::SP upd; - upd.reset(new document::DocumentUpdate(docType, document::DocumentId("groupdoc:footype:hable:foo"))); + upd.reset(new document::DocumentUpdate(repo, docType, document::DocumentId("groupdoc:footype:hable:foo"))); upd->addFieldPathUpdate(document::FieldPathUpdate::CP( new document::RemoveFieldPathUpdate("intfield", "testdoc.intfield > 0"))); msg.addUpdate(upd); diff --git a/documentapi/src/tests/messages/messages52test.cpp b/documentapi/src/tests/messages/messages52test.cpp index eaf8bbec8c4..8f5d7381500 100644 --- a/documentapi/src/tests/messages/messages52test.cpp +++ b/documentapi/src/tests/messages/messages52test.cpp @@ -91,7 +91,7 @@ Messages52Test::testUpdateDocumentMessage() const DocumentTypeRepo & repo = getTypeRepo(); const document::DocumentType & docType = *repo.getDocumentType("testdoc"); - auto docUpdate = std::make_shared<document::DocumentUpdate>(docType, document::DocumentId("doc:scheme:")); + auto docUpdate = std::make_shared<document::DocumentUpdate>(repo, docType, document::DocumentId("doc:scheme:")); docUpdate->addFieldPathUpdate(document::FieldPathUpdate::CP( new document::RemoveFieldPathUpdate("intfield", "testdoc.intfield > 0"))); diff --git a/documentapi/src/tests/policies/policies_test.cpp b/documentapi/src/tests/policies/policies_test.cpp index 7852136dfc7..3e804c30415 100644 --- a/documentapi/src/tests/policies/policies_test.cpp +++ b/documentapi/src/tests/policies/policies_test.cpp @@ -621,7 +621,7 @@ Test::testDocumentRouteSelector() EXPECT_TRUE(frame.testSelect(StringList().add("foo").add("bar"))); frame.setMessage(make_unique<UpdateDocumentMessage>( - make_shared<DocumentUpdate>(*_docType, DocumentId("doc:scheme:")))); + make_shared<DocumentUpdate>(*_repo, *_docType, DocumentId("doc:scheme:")))); EXPECT_TRUE(frame.testSelect(StringList().add("foo"))); put = make_unique<PutDocumentMessage>(make_shared<Document>(*_docType, DocumentId("doc:scheme:"))); @@ -650,7 +650,7 @@ Test::testDocumentRouteSelectorIgnore() EXPECT_EQUAL(0u, reply->getNumErrors()); frame.setMessage(make_unique<UpdateDocumentMessage>( - make_shared<DocumentUpdate>(*_docType, DocumentId("doc:scheme:")))); + make_shared<DocumentUpdate>(*_repo, *_docType, DocumentId("doc:scheme:")))); EXPECT_TRUE(frame.testSelect(StringList().add("docproc/cluster.foo"))); } diff --git a/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp b/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp index f9538a94c59..c1373a391f0 100644 --- a/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp +++ b/persistence/src/vespa/persistence/conformancetest/conformancetest.cpp @@ -897,10 +897,8 @@ void ConformanceTest::testUpdate() { const document::DocumentType *docType( testDocMan.getTypeRepo().getDocumentType("testdoctype1")); - document::DocumentUpdate::SP - update(new DocumentUpdate(*docType, doc1->getId())); - std::shared_ptr<document::AssignValueUpdate> assignUpdate( - new document::AssignValueUpdate(document::IntFieldValue(42))); + document::DocumentUpdate::SP update(new DocumentUpdate(testDocMan.getTypeRepo(), *docType, doc1->getId())); + std::shared_ptr<document::AssignValueUpdate> assignUpdate(new document::AssignValueUpdate(document::IntFieldValue(42))); document::FieldUpdate fieldUpdate(docType->getField("headerval")); fieldUpdate.addUpdate(*assignUpdate); update->addUpdate(fieldUpdate); diff --git a/searchcore/src/tests/proton/attribute/attribute_test.cpp b/searchcore/src/tests/proton/attribute/attribute_test.cpp index c41b6bdcb97..0e6bd2c74fe 100644 --- a/searchcore/src/tests/proton/attribute/attribute_test.cpp +++ b/searchcore/src/tests/proton/attribute/attribute_test.cpp @@ -445,7 +445,7 @@ TEST_F("require that attribute writer handles update", Fixture) schema.addAttributeField(Schema::AttributeField("a2", schema::DataType::INT32, CollectionType::SINGLE)); DocBuilder idb(schema); const document::DocumentType &dt(idb.getDocumentType()); - DocumentUpdate upd(dt, DocumentId("doc::1")); + DocumentUpdate upd(*idb.getDocumentTypeRepo(), dt, DocumentId("doc::1")); upd.addUpdate(FieldUpdate(upd.getType().getField("a1")) .addUpdate(ArithmeticValueUpdate(ArithmeticValueUpdate::Add, 5))); upd.addUpdate(FieldUpdate(upd.getType().getField("a2")) @@ -489,7 +489,7 @@ TEST_F("require that attribute writer handles predicate update", Fixture) EXPECT_EQUAL(2u, a1->getNumDocs()); const document::DocumentType &dt(idb.getDocumentType()); - DocumentUpdate upd(dt, DocumentId("doc::1")); + DocumentUpdate upd(*idb.getDocumentTypeRepo(), dt, DocumentId("doc::1")); PredicateFieldValue new_value(builder.feature("foo").value("bar").build()); upd.addUpdate(FieldUpdate(upd.getType().getField("a1")) .addUpdate(AssignValueUpdate(new_value))); @@ -678,7 +678,7 @@ TEST_F("require that attribute writer handles tensor assign update", Fixture) EXPECT_TRUE(tensor->equals(*tensor2)); const document::DocumentType &dt(builder.getDocumentType()); - DocumentUpdate upd(dt, DocumentId("doc::1")); + DocumentUpdate upd(*builder.getDocumentTypeRepo(), dt, DocumentId("doc::1")); auto new_tensor = createTensor({ {{{"x", "8"}, {"y", "9"}}, 11} }, {"x", "y"}); TensorFieldValue new_value; diff --git a/searchcore/src/tests/proton/documentdb/feedhandler/feedhandler_test.cpp b/searchcore/src/tests/proton/documentdb/feedhandler/feedhandler_test.cpp index e774728b41e..a1bce7174bf 100644 --- a/searchcore/src/tests/proton/documentdb/feedhandler/feedhandler_test.cpp +++ b/searchcore/src/tests/proton/documentdb/feedhandler/feedhandler_test.cpp @@ -316,7 +316,7 @@ struct UpdateContext { DocumentUpdate::SP update; BucketId bucketId; UpdateContext(const vespalib::string &docId, DocBuilder &builder) : - update(new DocumentUpdate(builder.getDocumentType(), DocumentId(docId))), + update(new DocumentUpdate(*builder.getDocumentTypeRepo(), builder.getDocumentType(), DocumentId(docId))), bucketId(BucketFactory::getBucketId(update->getId())) { } diff --git a/searchcore/src/tests/proton/documentdb/feedview/feedview_test.cpp b/searchcore/src/tests/proton/documentdb/feedview/feedview_test.cpp index a9fa79f513c..111b4047da3 100644 --- a/searchcore/src/tests/proton/documentdb/feedview/feedview_test.cpp +++ b/searchcore/src/tests/proton/documentdb/feedview/feedview_test.cpp @@ -478,11 +478,11 @@ struct DocumentContext DocumentContext::DocumentContext(const vespalib::string &docId, uint64_t timestamp, DocBuilder &builder) : doc(builder.startDocument(docId).startSummaryField("s1").addStr(docId).endField().endDocument().release()), - upd(new DocumentUpdate(builder.getDocumentType(), doc->getId())), + upd(new DocumentUpdate(*builder.getDocumentTypeRepo(), builder.getDocumentType(), doc->getId())), bid(BucketFactory::getNumBucketBits(), doc->getId().getGlobalId().convertToBucketId().getRawId()), ts(timestamp) {} -DocumentContext::~DocumentContext() {} +DocumentContext::~DocumentContext() = default; struct FeedTokenContext { diff --git a/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp b/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp index 9a9d896f2b9..e87e9209a17 100644 --- a/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp +++ b/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp @@ -122,7 +122,7 @@ public: } auto makeUpdate() { - auto upd(std::make_shared<DocumentUpdate>(_docType, docId)); + auto upd(std::make_shared<DocumentUpdate>(*_repo, _docType, docId)); upd->addUpdate(FieldUpdate(upd->getType().getField("string")). addUpdate(AssignValueUpdate(StringFieldValue("newval")))); return upd; @@ -136,6 +136,7 @@ public: TEST("require that toString() on derived classes are meaningful") { + DocumentTypeRepo repo; BucketId bucket_id1(42); BucketId bucket_id2(43); BucketId bucket_id3(44); @@ -146,7 +147,7 @@ TEST("require that toString() on derived classes are meaningful") MyStreamHandler stream_handler; DocumentIdT doc_id_limit = 15; DocumentId doc_id("doc:foo:bar"); - DocumentUpdate::SP update(new DocumentUpdate(*DataType::DOCUMENT, doc_id)); + DocumentUpdate::SP update(new DocumentUpdate(repo, *DataType::DOCUMENT, doc_id)); EXPECT_EQUAL("DeleteBucket(BucketId(0x0000000000000000), serialNum=0)", DeleteBucketOperation().toString()); diff --git a/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp b/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp index 73580416e65..7f065d0cc15 100644 --- a/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp +++ b/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp @@ -67,7 +67,9 @@ createDoc(const DocumentType &docType, const DocumentId &docId) document::DocumentUpdate::SP createUpd(const DocumentType& docType, const DocumentId &docId) { - return document::DocumentUpdate::SP(new document::DocumentUpdate(docType, docId)); + static std::vector<std::unique_ptr<document::DocumentTypeRepo>> repoList; + repoList.emplace_back(std::make_unique<document::DocumentTypeRepo>(docType)); + return std::make_shared<document::DocumentUpdate>(*repoList.back(), docType, docId); } storage::spi::ClusterState diff --git a/searchcore/src/vespa/searchcore/proton/feedoperation/updateoperation.cpp b/searchcore/src/vespa/searchcore/proton/feedoperation/updateoperation.cpp index d31f1faec77..824909d0431 100644 --- a/searchcore/src/vespa/searchcore/proton/feedoperation/updateoperation.cpp +++ b/searchcore/src/vespa/searchcore/proton/feedoperation/updateoperation.cpp @@ -51,12 +51,11 @@ UpdateOperation::serializeUpdate(vespalib::nbostream &os) const } void -UpdateOperation::deserializeUpdate(vespalib::nbostream &is, const document::DocumentTypeRepo &repo) +UpdateOperation::deserializeUpdate(vespalib::nbostream && is, const document::DocumentTypeRepo &repo) { - document::ByteBuffer buf(is.peek(), is.size()); - DocumentUpdate::UP update = (getType() == UPDATE_42) ? DocumentUpdate::create42(repo, buf) : DocumentUpdate::createHEAD(repo, buf); - is.adjustReadPos(buf.getPos()); - _upd = std::move(update); + _upd = (getType() == UPDATE_42) + ? DocumentUpdate::create42(repo, is) + : DocumentUpdate::createHEAD(repo, std::move(is)); } void @@ -73,7 +72,7 @@ UpdateOperation::deserialize(vespalib::nbostream &is, const DocumentTypeRepo &re { DocumentOperation::deserialize(is, repo); try { - deserializeUpdate(is, repo); + deserializeUpdate(std::move(is), repo); } catch (document::DocumentTypeNotFoundException &e) { LOG(warning, "Failed deserialize update operation using unknown document type '%s'", e.getDocumentTypeName().c_str()); @@ -87,14 +86,14 @@ UpdateOperation::deserializeUpdate(const DocumentTypeRepo &repo) { vespalib::nbostream stream; serializeUpdate(stream); - deserializeUpdate(stream, repo); + deserializeUpdate(std::move(stream), repo); } -vespalib::string UpdateOperation::toString() const { +vespalib::string +UpdateOperation::toString() const { return make_string("%s(%s, %s)", ((getType() == FeedOperation::UPDATE_42) ? "Update42" : "Update"), - _upd.get() ? - _upd->getId().getScheme().toString().c_str() : "NULL", + _upd.get() ? _upd->getId().getScheme().toString().c_str() : "NULL", docArgsToString().c_str()); } diff --git a/searchcore/src/vespa/searchcore/proton/feedoperation/updateoperation.h b/searchcore/src/vespa/searchcore/proton/feedoperation/updateoperation.h index 99dcbfbce6c..554778728f0 100644 --- a/searchcore/src/vespa/searchcore/proton/feedoperation/updateoperation.h +++ b/searchcore/src/vespa/searchcore/proton/feedoperation/updateoperation.h @@ -19,7 +19,7 @@ private: const storage::spi::Timestamp ×tamp, const DocumentUpdateSP &upd); void serializeUpdate(vespalib::nbostream &os) const; - void deserializeUpdate(vespalib::nbostream &is, const document::DocumentTypeRepo &repo); + void deserializeUpdate(vespalib::nbostream && is, const document::DocumentTypeRepo &repo); public: UpdateOperation(); UpdateOperation(Type type); diff --git a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp index bab3494ca5c..f774c953af4 100644 --- a/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp +++ b/searchcore/src/vespa/searchcore/proton/persistenceengine/persistenceengine.cpp @@ -377,6 +377,7 @@ PersistenceEngine::update(const Bucket& b, Timestamp t, const DocumentUpdate::SP upd->getId().toString().c_str(), state.message().c_str())); } } + upd->eagerDeserialize(); std::shared_lock<std::shared_timed_mutex> rguard(_rwMutex); DocTypeName docType(upd->getType()); LOG(spam, "update(%s, %" PRIu64 ", (\"%s\", \"%s\"), createIfNonExistent='%s')", diff --git a/storage/src/tests/bucketdb/bucketmanagertest.cpp b/storage/src/tests/bucketdb/bucketmanagertest.cpp index d12e6b90b2a..829a080ad01 100644 --- a/storage/src/tests/bucketdb/bucketmanagertest.cpp +++ b/storage/src/tests/bucketdb/bucketmanagertest.cpp @@ -723,6 +723,7 @@ public: auto createUpdateCommand(const document::BucketId& bucket) const { auto update = std::make_shared<document::DocumentUpdate>( + _self._node->getTestDocMan().getTypeRepo(), *_self._node->getTestDocMan().getTypeRepo() .getDocumentType("testdoctype1"), document::DocumentId("id:foo:testdoctype1::bar2")); diff --git a/storage/src/tests/distributor/externaloperationhandlertest.cpp b/storage/src/tests/distributor/externaloperationhandlertest.cpp index 81b0293b0c0..54aca78d13d 100644 --- a/storage/src/tests/distributor/externaloperationhandlertest.cpp +++ b/storage/src/tests/distributor/externaloperationhandlertest.cpp @@ -200,6 +200,7 @@ std::shared_ptr<api::UpdateCommand> ExternalOperationHandlerTest::makeUpdateComm const vespalib::string& doc_type, const vespalib::string& id) const { auto update = std::make_shared<document::DocumentUpdate>( + _testDocMan.getTypeRepo(), *_testDocMan.getTypeRepo().getDocumentType(doc_type), document::DocumentId(id)); return std::make_shared<api::UpdateCommand>( diff --git a/storage/src/tests/distributor/twophaseupdateoperationtest.cpp b/storage/src/tests/distributor/twophaseupdateoperationtest.cpp index 28602124045..ea2cc00c642 100644 --- a/storage/src/tests/distributor/twophaseupdateoperationtest.cpp +++ b/storage/src/tests/distributor/twophaseupdateoperationtest.cpp @@ -294,7 +294,7 @@ TwoPhaseUpdateOperationTest::sendUpdate(const std::string& bucketState, document::DocumentUpdate::SP update; if (!options._withError) { update = std::make_shared<document::DocumentUpdate>( - *_doc_type, + *_repo, *_doc_type, document::DocumentId(document::DocIdString("test", "test"))); document::FieldUpdate fup(_doc_type->getField("headerval")); fup.addUpdate(ArithmeticValueUpdate(ArithmeticValueUpdate::Add, 10)); @@ -304,7 +304,7 @@ TwoPhaseUpdateOperationTest::sendUpdate(const std::string& bucketState, // part of the Get. Just a sneaky way to force an eval error. auto* badDocType = _repo->getDocumentType("testdoctype2"); update = std::make_shared<document::DocumentUpdate>( - *badDocType, + *_repo, *badDocType, document::DocumentId(document::DocIdString("test", "test"))); document::FieldUpdate fup(badDocType->getField("onlyinchild")); fup.addUpdate(ArithmeticValueUpdate(ArithmeticValueUpdate::Add, 10)); diff --git a/storage/src/tests/distributor/updateoperationtest.cpp b/storage/src/tests/distributor/updateoperationtest.cpp index 92474728957..9ce862f5db8 100644 --- a/storage/src/tests/distributor/updateoperationtest.cpp +++ b/storage/src/tests/distributor/updateoperationtest.cpp @@ -75,8 +75,7 @@ std::shared_ptr<UpdateOperation> UpdateOperation_Test::sendUpdate(const std::string& bucketState) { document::DocumentUpdate::SP update( - new document::DocumentUpdate( - *_html_type, + new document::DocumentUpdate(*_repo, *_html_type, document::DocumentId(document::DocIdString("test", "test")))); _bId = getExternalOperationHandler().getBucketId(update->getId()); diff --git a/storage/src/tests/persistence/filestorage/filestormanagertest.cpp b/storage/src/tests/persistence/filestorage/filestormanagertest.cpp index 838df87662f..369e820f987 100644 --- a/storage/src/tests/persistence/filestorage/filestormanagertest.cpp +++ b/storage/src/tests/persistence/filestorage/filestormanagertest.cpp @@ -2725,6 +2725,7 @@ void FileStorManagerTest::update_command_size_is_added_to_metric() { document::BucketId bucket(16, 4000); createBucket(bucket, 0); auto update = std::make_shared<document::DocumentUpdate>( + _node->getTestDocMan().getTypeRepo(), _node->getTestDocMan().createRandomDocument()->getType(), document::DocumentId("id:foo:testdoctype1::bar")); auto cmd = std::make_shared<api::UpdateCommand>( diff --git a/storage/src/tests/persistence/persistencetestutils.cpp b/storage/src/tests/persistence/persistencetestutils.cpp index f15921e447d..368eae104e8 100644 --- a/storage/src/tests/persistence/persistencetestutils.cpp +++ b/storage/src/tests/persistence/persistencetestutils.cpp @@ -223,16 +223,11 @@ PersistenceTestUtils::doGetOnDisk( } document::DocumentUpdate::SP -PersistenceTestUtils::createBodyUpdate( - const document::DocumentId& docId, - const document::FieldValue& updateValue) +PersistenceTestUtils::createBodyUpdate(const document::DocumentId& docId, const document::FieldValue& updateValue) { - const DocumentType* docType(_env->_component.getTypeRepo() - ->getDocumentType("testdoctype1")); - document::DocumentUpdate::SP update( - new document::DocumentUpdate(*docType, docId)); - std::shared_ptr<document::AssignValueUpdate> assignUpdate( - new document::AssignValueUpdate(updateValue)); + const DocumentType* docType(_env->_component.getTypeRepo()->getDocumentType("testdoctype1")); + document::DocumentUpdate::SP update(new document::DocumentUpdate(*_env->_component.getTypeRepo(), *docType, docId)); + std::shared_ptr<document::AssignValueUpdate> assignUpdate(new document::AssignValueUpdate(updateValue)); document::FieldUpdate fieldUpdate(docType->getField("content")); fieldUpdate.addUpdate(*assignUpdate); update->addUpdate(fieldUpdate); @@ -240,16 +235,11 @@ PersistenceTestUtils::createBodyUpdate( } document::DocumentUpdate::SP -PersistenceTestUtils::createHeaderUpdate( - const document::DocumentId& docId, - const document::FieldValue& updateValue) +PersistenceTestUtils::createHeaderUpdate(const document::DocumentId& docId, const document::FieldValue& updateValue) { - const DocumentType* docType(_env->_component.getTypeRepo() - ->getDocumentType("testdoctype1")); - document::DocumentUpdate::SP update( - new document::DocumentUpdate(*docType, docId)); - std::shared_ptr<document::AssignValueUpdate> assignUpdate( - new document::AssignValueUpdate(updateValue)); + const DocumentType* docType(_env->_component.getTypeRepo()->getDocumentType("testdoctype1")); + document::DocumentUpdate::SP update(new document::DocumentUpdate(*_env->_component.getTypeRepo(), *docType, docId)); + std::shared_ptr<document::AssignValueUpdate> assignUpdate(new document::AssignValueUpdate(updateValue)); document::FieldUpdate fieldUpdate(docType->getField("headerval")); fieldUpdate.addUpdate(*assignUpdate); update->addUpdate(fieldUpdate); diff --git a/storage/src/tests/persistence/testandsettest.cpp b/storage/src/tests/persistence/testandsettest.cpp index c729df1e7eb..686e10ba5ef 100644 --- a/storage/src/tests/persistence/testandsettest.cpp +++ b/storage/src/tests/persistence/testandsettest.cpp @@ -189,7 +189,7 @@ std::unique_ptr<api::UpdateCommand> TestAndSetTest::conditional_update_test( { putTestDocument(matchingHeader, timestampOne); - auto docUpdate = std::make_shared<document::DocumentUpdate>(testDoc->getType(), testDocId); + auto docUpdate = std::make_shared<document::DocumentUpdate>(_env->_testDocMan.getTypeRepo(), testDoc->getType(), testDocId); auto fieldUpdate = document::FieldUpdate(testDoc->getField("content")); fieldUpdate.addUpdate(document::AssignValueUpdate(NEW_CONTENT)); docUpdate->addUpdate(fieldUpdate); diff --git a/storage/src/tests/storageserver/changedbucketownershiphandlertest.cpp b/storage/src/tests/storageserver/changedbucketownershiphandlertest.cpp index 7df598bed97..98ad8761736 100644 --- a/storage/src/tests/storageserver/changedbucketownershiphandlertest.cpp +++ b/storage/src/tests/storageserver/changedbucketownershiphandlertest.cpp @@ -597,25 +597,19 @@ ChangedBucketOwnershipHandlerTest::testAbortOutdatedPutOperation() void ChangedBucketOwnershipHandlerTest::testAbortOutdatedUpdateCommand() { - const document::DocumentType* docType(_testDocRepo.getTypeRepo() - .getDocumentType("testdoctype1")); + const document::DocumentType* docType(_testDocRepo.getTypeRepo().getDocumentType("testdoctype1")); document::DocumentId docId("id:foo:testdoctype1::bar"); - document::DocumentUpdate::SP update( - std::make_shared<document::DocumentUpdate>(*docType, docId)); - CPPUNIT_ASSERT(changeAbortsMessage<api::UpdateCommand>( - getBucketToAbort(), update, api::Timestamp(1234))); - CPPUNIT_ASSERT(!changeAbortsMessage<api::UpdateCommand>( - getBucketToAllow(), update, api::Timestamp(1234))); + auto update(std::make_shared<document::DocumentUpdate>(_testDocRepo.getTypeRepo(), *docType, docId)); + CPPUNIT_ASSERT(changeAbortsMessage<api::UpdateCommand>(getBucketToAbort(), update, api::Timestamp(1234))); + CPPUNIT_ASSERT(!changeAbortsMessage<api::UpdateCommand>(getBucketToAllow(), update, api::Timestamp(1234))); } void ChangedBucketOwnershipHandlerTest::testAbortOutdatedRemoveCommand() { document::DocumentId docId("id:foo:testdoctype1::bar"); - CPPUNIT_ASSERT(changeAbortsMessage<api::RemoveCommand>( - getBucketToAbort(), docId, api::Timestamp(1234))); - CPPUNIT_ASSERT(!changeAbortsMessage<api::RemoveCommand>( - getBucketToAllow(), docId, api::Timestamp(1234))); + CPPUNIT_ASSERT(changeAbortsMessage<api::RemoveCommand>(getBucketToAbort(), docId, api::Timestamp(1234))); + CPPUNIT_ASSERT(!changeAbortsMessage<api::RemoveCommand>(getBucketToAllow(), docId, api::Timestamp(1234))); } void diff --git a/storage/src/tests/storageserver/documentapiconvertertest.cpp b/storage/src/tests/storageserver/documentapiconvertertest.cpp index 695ae17c5d4..40d561bd589 100644 --- a/storage/src/tests/storageserver/documentapiconvertertest.cpp +++ b/storage/src/tests/storageserver/documentapiconvertertest.cpp @@ -181,7 +181,7 @@ void DocumentApiConverterTest::testForwardedPut() void DocumentApiConverterTest::testUpdate() { - auto update = std::make_shared<document::DocumentUpdate>(_html_type, defaultDocId); + auto update = std::make_shared<document::DocumentUpdate>(*_repo, _html_type, defaultDocId); documentapi::UpdateDocumentMessage updateMsg(update); updateMsg.setOldTimestamp(1234); updateMsg.setNewTimestamp(5678); @@ -327,19 +327,19 @@ DocumentApiConverterTest::testBatchDocumentUpdate() { document::DocumentId docId(document::UserDocIdString("userdoc:test:1234:test1")); - auto update = std::make_shared<document::DocumentUpdate>(_html_type, docId); + auto update = std::make_shared<document::DocumentUpdate>(*_repo, _html_type, docId); updates.push_back(update); } { document::DocumentId docId(document::UserDocIdString("userdoc:test:1234:test2")); - auto update = std::make_shared<document::DocumentUpdate>(_html_type, docId); + auto update = std::make_shared<document::DocumentUpdate>(*_repo, _html_type, docId); updates.push_back(update); } { document::DocumentId docId(document::UserDocIdString("userdoc:test:1234:test3")); - auto update = std::make_shared<document::DocumentUpdate>(_html_type, docId); + auto update = std::make_shared<document::DocumentUpdate>(*_repo, _html_type, docId); updates.push_back(update); } diff --git a/storageapi/src/tests/mbusprot/storageprotocoltest.cpp b/storageapi/src/tests/mbusprot/storageprotocoltest.cpp index a809d80e0f5..cfc69bcde45 100644 --- a/storageapi/src/tests/mbusprot/storageprotocoltest.cpp +++ b/storageapi/src/tests/mbusprot/storageprotocoltest.cpp @@ -294,7 +294,7 @@ void StorageProtocolTest::testUpdate51() { ScopedName test("testUpdate51"); - document::DocumentUpdate::SP update(new document::DocumentUpdate(*_testDoc->getDataType(), _testDoc->getId())); + document::DocumentUpdate::SP update(new document::DocumentUpdate(_docMan.getTypeRepo(), *_testDoc->getDataType(), _testDoc->getId())); std::shared_ptr<document::AssignValueUpdate> assignUpdate(new document::AssignValueUpdate(document::IntFieldValue(17))); document::FieldUpdate fieldUpdate(_testDoc->getField("headerval")); fieldUpdate.addUpdate(*assignUpdate); @@ -912,7 +912,7 @@ StorageProtocolTest::testUpdateCommand52() { ScopedName test("testUpdateCommand52"); - document::DocumentUpdate::SP update(new document::DocumentUpdate(*_testDoc->getDataType(), _testDoc->getId())); + document::DocumentUpdate::SP update(new document::DocumentUpdate(_docMan.getTypeRepo(), *_testDoc->getDataType(), _testDoc->getId())); UpdateCommand::SP cmd(new UpdateCommand(_bucket, update, 14)); cmd->setCondition(TestAndSetCondition(CONDITION_STRING)); diff --git a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.cpp b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.cpp index 44050264484..47b77af74a5 100644 --- a/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.cpp +++ b/storageapi/src/vespa/storageapi/mbusprot/protocolserialization5_0.cpp @@ -228,9 +228,8 @@ ProtocolSerialization5_0::onDecodeUpdateCommand(BBuf& buf) const uint32_t size = SH::getInt(buf); if (size != 0) { - document::ByteBuffer bbuf(buf.getBufferAtPos(), size); + update = document::DocumentUpdate::createHEAD(getTypeRepo(), vespalib::nbostream(buf.getBufferAtPos(), size)); buf.incPos(size); - update = document::DocumentUpdate::createHEAD(getTypeRepo(), bbuf); } document::Bucket bucket = getBucket(buf); |