diff options
84 files changed, 679 insertions, 531 deletions
diff --git a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/AutoscalingMetrics.java b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/AutoscalingMetrics.java index 29a54548256..8bb6be16e4a 100644 --- a/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/AutoscalingMetrics.java +++ b/config-model/src/main/java/com/yahoo/vespa/model/admin/monitoring/AutoscalingMetrics.java @@ -11,7 +11,8 @@ import java.util.Set; import java.util.stream.Collectors; /** - * Metrics used for autoscaling + * Metrics used for autoscaling. + * See com.yahoo.vespa.hosted.provision.autoscale.MetricsResponse * * @author bratseth */ @@ -23,9 +24,12 @@ public class AutoscalingMetrics { List<String> metrics = new ArrayList<>(); metrics.add(HostedNodeAdminMetrics.CPU_UTIL.baseName()); + metrics.add(HostedNodeAdminMetrics.GPU_UTIL.baseName()); // Memory util metrics.add(HostedNodeAdminMetrics.MEM_UTIL.baseName()); // node level - default + metrics.add(HostedNodeAdminMetrics.GPU_MEM_USED.baseName()); + metrics.add(HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()); metrics.add(SearchNodeMetrics.CONTENT_PROTON_RESOURCE_USAGE_MEMORY.average()); // the basis for blocking // Disk util diff --git a/document/src/tests/documentcalculatortestcase.cpp b/document/src/tests/documentcalculatortestcase.cpp index 7e27dcf2d36..dafc87f4ccd 100644 --- a/document/src/tests/documentcalculatortestcase.cpp +++ b/document/src/tests/documentcalculatortestcase.cpp @@ -24,7 +24,7 @@ TEST_F(DocumentCalculatorTest, testConstant) { auto variables = std::make_unique<select::VariableMap>(); DocumentCalculator calc(getRepo(), "4.0"); - Document doc(*_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); + Document doc(_testRepo.getTypeRepo(), *_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); EXPECT_EQ(4.0, calc.evaluate(doc, std::move(variables))); } @@ -32,7 +32,7 @@ TEST_F(DocumentCalculatorTest, testSimple) { auto variables = std::make_unique<select::VariableMap>(); DocumentCalculator calc(getRepo(), "(3 + 5) / 2"); - Document doc(*_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); + Document doc(_testRepo.getTypeRepo(), *_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); EXPECT_EQ(4.0, calc.evaluate(doc, std::move(variables))); } @@ -42,7 +42,7 @@ TEST_F(DocumentCalculatorTest, testVariables) { (*variables)["y"] = 5.0; DocumentCalculator calc(getRepo(), "($x + $y) / 2"); - Document doc(*_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); + Document doc(_testRepo.getTypeRepo(), *_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); EXPECT_EQ(4.0, calc.evaluate(doc, std::move(variables))); } @@ -53,7 +53,7 @@ TEST_F(DocumentCalculatorTest, testFields) { DocumentCalculator calc(getRepo(), "(testdoctype1.headerval + testdoctype1" ".hfloatval) / testdoctype1.headerlongval"); - Document doc(*_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); + Document doc(_testRepo.getTypeRepo(), *_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); doc.setValue(doc.getField("headerval"), IntFieldValue(5)); doc.setValue(doc.getField("hfloatval"), FloatFieldValue(3.0)); doc.setValue(doc.getField("headerlongval"), LongFieldValue(2)); @@ -67,7 +67,7 @@ TEST_F(DocumentCalculatorTest, testFieldsDivZero) { DocumentCalculator calc(getRepo(), "(testdoctype1.headerval + testdoctype1" ".hfloatval) / testdoctype1.headerlongval"); - Document doc(*_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); + Document doc(_testRepo.getTypeRepo(), *_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); doc.setValue(doc.getField("headerval"), IntFieldValue(5)); doc.setValue(doc.getField("hfloatval"), FloatFieldValue(3.0)); doc.setValue(doc.getField("headerlongval"), LongFieldValue(0)); @@ -79,7 +79,7 @@ TEST_F(DocumentCalculatorTest, testDivideByZero) { auto variables = std::make_unique<select::VariableMap>(); DocumentCalculator calc(getRepo(), "(3 + 5) / 0"); - Document doc(*_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); + Document doc(_testRepo.getTypeRepo(), *_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); EXPECT_THROW(calc.evaluate(doc, std::move(variables)), vespalib::IllegalArgumentException); } @@ -88,7 +88,7 @@ TEST_F(DocumentCalculatorTest, testModByZero) { auto variables = std::make_unique<select::VariableMap>(); DocumentCalculator calc(getRepo(), "(3 + 5) % 0"); - Document doc(*_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); + Document doc(_testRepo.getTypeRepo(), *_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); EXPECT_THROW(calc.evaluate(doc, std::move(variables)), vespalib::IllegalArgumentException); } @@ -98,7 +98,7 @@ TEST_F(DocumentCalculatorTest, testFieldNotSet) { DocumentCalculator calc(getRepo(), "(testdoctype1.headerval + testdoctype1" ".hfloatval) / testdoctype1.headerlongval"); - Document doc(*_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); + Document doc(_testRepo.getTypeRepo(), *_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); doc.setValue(doc.getField("hfloatval"), FloatFieldValue(3.0)); doc.setValue(doc.getField("headerlongval"), LongFieldValue(2)); EXPECT_THROW(calc.evaluate(doc, std::move(variables)), @@ -111,7 +111,7 @@ TEST_F(DocumentCalculatorTest, testFieldNotFound) { "(testdoctype1.mynotfoundfield + testdoctype1" ".hfloatval) / testdoctype1.headerlongval"); - Document doc(*_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); + Document doc(_testRepo.getTypeRepo(), *_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); doc.setValue(doc.getField("hfloatval"), FloatFieldValue(3.0)); doc.setValue(doc.getField("headerlongval"), LongFieldValue(2)); EXPECT_THROW(calc.evaluate(doc, std::move(variables)), @@ -122,7 +122,7 @@ TEST_F(DocumentCalculatorTest, testByteSubtractionZeroResult) { auto variables = std::make_unique<select::VariableMap>(); DocumentCalculator calc(getRepo(), "testdoctype1.byteval - 3"); - Document doc(*_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); + Document doc(_testRepo.getTypeRepo(), *_testRepo.getDocumentType("testdoctype1"), DocumentId("id:ns:testdoctype1::foo")); doc.setValue(doc.getField("byteval"), ByteFieldValue(3)); EXPECT_EQ(0.0, calc.evaluate(doc, std::move(variables))); } diff --git a/document/src/tests/documentselectparsertest.cpp b/document/src/tests/documentselectparsertest.cpp index 5e14a080f27..13ad2873bfa 100644 --- a/document/src/tests/documentselectparsertest.cpp +++ b/document/src/tests/documentselectparsertest.cpp @@ -120,7 +120,7 @@ Document::SP DocumentSelectParserTest::createDoc( uint64_t hlong) { const DocumentType* type = _repo->getDocumentType(doctype); - auto doc = std::make_shared<Document>(*type, DocumentId(id)); + auto doc = std::make_shared<Document>(*_repo, *type, DocumentId(id)); doc->setValue(doc->getField("headerval"), IntFieldValue(hint)); if (hlong != 0) { @@ -1662,7 +1662,7 @@ TEST_F(DocumentSelectParserTest, test_parse_utilities_handle_malformed_input) TEST_F(DocumentSelectParserTest, imported_field_references_are_treated_as_valid_field_with_missing_value) { const DocumentType* type = _repo->getDocumentType("with_imported"); ASSERT_TRUE(type != nullptr); - Document doc(*type, DocumentId("id::with_imported::foo")); + Document doc(*_repo, *type, DocumentId("id::with_imported::foo")); PARSE("with_imported.my_imported_field == null", doc, True); PARSE("with_imported.my_imported_field != null", doc, False); @@ -1674,7 +1674,7 @@ TEST_F(DocumentSelectParserTest, imported_field_references_are_treated_as_valid_ TEST_F(DocumentSelectParserTest, imported_field_references_only_support_for_simple_expressions) { const DocumentType* type = _repo->getDocumentType("with_imported"); ASSERT_TRUE(type != nullptr); - Document doc(*type, DocumentId("id::with_imported::foo")); + Document doc(*_repo, *type, DocumentId("id::with_imported::foo")); PARSE("with_imported.my_imported_field.foo", doc, Invalid); PARSE("with_imported.my_imported_field[0]", doc, Invalid); diff --git a/document/src/tests/documenttestcase.cpp b/document/src/tests/documenttestcase.cpp index bc4065438e6..2e9e783470c 100644 --- a/document/src/tests/documenttestcase.cpp +++ b/document/src/tests/documenttestcase.cpp @@ -136,8 +136,8 @@ TEST(DocumentTest, testTraversing) type.addField(primitive1); type.addField(structl1s1); - Document doc(type, DocumentId("id:ns:test::1")); - doc.setValue(primitive1, IntFieldValue(1)); + auto doc = Document::make_without_repo(type, DocumentId("id:ns:test::1")); + doc->setValue(primitive1, IntFieldValue(1)); StructFieldValue l1s1(struct3); l1s1.setValue(primitive1, IntFieldValue(2)); @@ -159,11 +159,11 @@ TEST(DocumentTest, testTraversing) l2s1.setValue(sarrF, sarr1); l1s1.setValue(s2, l2s1); - doc.setValue(structl1s1, l1s1); + doc->setValue(structl1s1, l1s1); Handler fullTraverser; FieldPath empty; - doc.iterateNested(empty.getFullRange(), fullTraverser); + doc->iterateNested(empty.getFullRange(), fullTraverser); EXPECT_EQ(fullTraverser.getResult(), std::string("<0:P-0<0:P-0<0:P-0P-0[P-0P-1P-2][<0:P-0P-0><1:P-1P-1>]>>>")); } @@ -208,14 +208,14 @@ TEST(DocumentTest, testVariables) iiiaV.add(iiaV); } - Document doc(type, DocumentId("id:ns:test::1")); - doc.setValue(iiiarrF, iiiaV); + auto doc = Document::make_without_repo(type, DocumentId("id:ns:test::1")); + doc->setValue(iiiarrF, iiiaV); { VariableIteratorHandler handler; FieldPath path; type.buildFieldPath(path, "iiiarray[$x][$y][$z]"); - doc.iterateNested(path.getFullRange(), handler); + doc->iterateNested(path.getFullRange(), handler); std::string fasit = "x: 0,y: 0,z: 0, - 1\n" @@ -315,7 +315,7 @@ TEST(DocumentTest, testModifyDocument) type.addField(primitive1); type.addField(structl1s1); - Document::UP doc(new Document(type, DocumentId("id:ns:test::1"))); + auto doc = Document::make_without_repo(type, DocumentId("id:ns:test::1")); doc->setValue(primitive1, IntFieldValue(1)); StructFieldValue l1s1(struct3); @@ -389,7 +389,7 @@ TEST(DocumentTest, testSimpleUsage) type->addField(strF); DocumentTypeRepo repo(*type); - Document value(*repo.getDocumentType("test"), DocumentId("id:ns:test::1")); + Document value(repo, *repo.getDocumentType("test"), DocumentId("id:ns:test::1")); // Initially empty EXPECT_EQ(size_t(0), value.getSetFieldCount()); @@ -412,7 +412,7 @@ TEST(DocumentTest, testSimpleUsage) // Serialize & equality nbostream buffer; value.serialize(buffer); - Document value2(*repo.getDocumentType("test"), + Document value2(repo, *repo.getDocumentType("test"), DocumentId("id::test:n=3:foo")); EXPECT_TRUE(value != value2); value2.deserialize(repo, buffer); @@ -508,7 +508,7 @@ TEST(DocumentTest, testSimpleUsage) // Refuse to accept non-document types try{ StructDataType otherType("foo", 4); - Document value6(otherType, DocumentId("id:ns:foo::1")); + auto doc = Document::make_without_repo(otherType, DocumentId("id:ns:foo::1")); FAIL() << "Didn't complain about non-document type"; } catch (std::exception& e) { EXPECT_THAT(e.what(), HasSubstr("Cannot generate a document with non-document type")); @@ -706,7 +706,7 @@ TEST(DocumentTest,testReadSerializedAllVersions) // Create a memory instance of document { - Document doc(*docType, DocumentId("id:ns:serializetest::http://test.doc.id/")); + Document doc(repo, *docType, DocumentId("id:ns:serializetest::http://test.doc.id/")); doc.setValue("intfield", IntFieldValue::make(5)); doc.setValue("floatfield", FloatFieldValue::make(-9.23)); doc.setValue("stringfield", StringFieldValue::make("This is a string.")); @@ -714,7 +714,7 @@ TEST(DocumentTest,testReadSerializedAllVersions) doc.setValue("doublefield", DoubleFieldValue::make(98374532.398820)); doc.setValue("bytefield", ByteFieldValue::make(-2)); doc.setValue("rawfield", std::make_unique<RawFieldValue>("RAW DATA", 8)); - Document docInDoc(*docInDocType, DocumentId("id:ns:docindoc::http://doc.in.doc/")); + Document docInDoc(repo, *docInDocType, DocumentId("id:ns:docindoc::http://doc.in.doc/")); docInDoc.setValue("stringindocfield", StringFieldValue::make("Elvis is dead")); doc.setValue("docfield", docInDoc); ArrayFieldValue floatArray(*arrayOfFloatDataType); @@ -828,7 +828,7 @@ TEST(DocumentTest, testGenerateSerializedFile) { const std::string file_name = TEST_PATH("data/crossplatform-java-cpp-doctypes.cfg"); DocumentTypeRepo repo(readDocumenttypesConfig(file_name)); - Document doc(*repo.getDocumentType("serializetest"), DocumentId("id:ns:serializetest::http://test.doc.id/")); + Document doc(repo, *repo.getDocumentType("serializetest"), DocumentId("id:ns:serializetest::http://test.doc.id/")); doc.setValue("intfield", IntFieldValue::make(5)); doc.setValue("floatfield", FloatFieldValue::make(-9.23)); @@ -841,7 +841,7 @@ TEST(DocumentTest, testGenerateSerializedFile) const DocumentType *docindoc_type = repo.getDocumentType("docindoc"); EXPECT_TRUE(docindoc_type); - Document embedDoc(*docindoc_type, DocumentId("id:ns:docindoc::http://embedded")); + Document embedDoc(repo, *docindoc_type, DocumentId("id:ns:docindoc::http://embedded")); doc.setValue("docfield", embedDoc); @@ -949,7 +949,7 @@ TEST(DocumentTest, testUnknownEntries) DocumentTypeRepo repo(type2); - Document doc1(type1, DocumentId("id:ns:test::1")); + Document doc1(repo, type1, DocumentId("id:ns:test::1")); doc1.setValue(field1, IntFieldValue(1)); doc1.setValue(field2, IntFieldValue(2)); doc1.setValue(field3, IntFieldValue(3)); diff --git a/document/src/tests/documenttypetestcase.cpp b/document/src/tests/documenttypetestcase.cpp index 95ee3f4deed..df6d8aa900f 100644 --- a/document/src/tests/documenttypetestcase.cpp +++ b/document/src/tests/documenttypetestcase.cpp @@ -108,7 +108,7 @@ TEST(DocumentTypeTest, testMultipleInheritance) EXPECT_TRUE(docType3->hasField("tmp")); EXPECT_TRUE(docType3->hasField("tall")); - Document doc(*docType3, DocumentId("id:ns:test3::1")); + Document doc(repo, *docType3, DocumentId("id:ns:test3::1")); IntFieldValue intVal(3); doc.setValue(doc.getField("nalle"), intVal); diff --git a/document/src/tests/documentupdatetestcase.cpp b/document/src/tests/documentupdatetestcase.cpp index 7a5d88d1013..3fbccaa155f 100644 --- a/document/src/tests/documentupdatetestcase.cpp +++ b/document/src/tests/documentupdatetestcase.cpp @@ -141,7 +141,7 @@ TEST(DocumentUpdateTest, testSimpleUsage) auto docUpdateCopy(DocumentUpdate::createHEAD(repo, docBuf)); // Create a test document - Document doc(*docType, DocumentId("id:ns:test::1")); + Document doc(repo, *docType, DocumentId("id:ns:test::1")); doc.setValue("bytef", ByteFieldValue::make(0)); doc.setValue("intf", IntFieldValue::make(5)); ArrayFieldValue array(*arrayType); @@ -417,7 +417,7 @@ WeightedSetAutoCreateFixture::~WeightedSetAutoCreateFixture() = default; WeightedSetAutoCreateFixture::WeightedSetAutoCreateFixture() : repo(makeConfig()), docType(repo.getDocumentType("test")), - doc(*docType, DocumentId("id:ns:test::1")), + doc(repo, *docType, DocumentId("id:ns:test::1")), field(docType->getField("strwset")), update(repo, *docType, DocumentId("id:ns:test::1")) { @@ -1355,7 +1355,7 @@ struct UpdateToEmptyDocumentFixture { Document::UP make_empty_doc() { vespalib::nbostream stream; { - Document doc(doc_type, DocumentId("id:test:test::0")); + Document doc(*repo, doc_type, DocumentId("id:test:test::0")); VespaDocumentSerializer serializer(stream); serializer.write(doc); } diff --git a/document/src/tests/fieldpathupdatetestcase.cpp b/document/src/tests/fieldpathupdatetestcase.cpp index a32face5e55..e9f984c9586 100644 --- a/document/src/tests/fieldpathupdatetestcase.cpp +++ b/document/src/tests/fieldpathupdatetestcase.cpp @@ -133,8 +133,7 @@ FieldPathUpdateTestCase::TearDown() TEST_F(FieldPathUpdateTestCase, testRemoveField) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::things:thangs")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::things:thangs")); EXPECT_TRUE(doc->hasValue("strfoo") == false); doc->setValue("strfoo", StringFieldValue("cocacola")); EXPECT_EQ(vespalib::string("cocacola"), doc->getValue("strfoo")->getAsString()); @@ -146,8 +145,7 @@ TEST_F(FieldPathUpdateTestCase, testRemoveField) TEST_F(FieldPathUpdateTestCase, testApplyRemoveMultiList) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::things:thangs")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::things:thangs")); EXPECT_TRUE(doc->hasValue("strarray") == false); { ArrayFieldValue strArray(doc->getType().getField("strarray").getDataType()); @@ -171,8 +169,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyRemoveMultiList) TEST_F(FieldPathUpdateTestCase, testApplyRemoveMultiList2) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::things:thangs")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::things:thangs")); EXPECT_TRUE(doc->hasValue("strarray") == false); { ArrayFieldValue strArray(doc->getType().getField("strarray").getDataType()); @@ -195,8 +192,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyRemoveMultiList2) TEST_F(FieldPathUpdateTestCase, testApplyRemoveEntireListField) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::things:thangs")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::things:thangs")); EXPECT_TRUE(doc->hasValue("strarray") == false); { ArrayFieldValue strArray(doc->getType().getField("strarray").getDataType()); @@ -214,8 +210,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyRemoveEntireListField) TEST_F(FieldPathUpdateTestCase, testApplyRemoveMultiWset) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::helan:halvan")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::helan:halvan")); EXPECT_TRUE(doc->hasValue("strwset") == false); { WeightedSetFieldValue strWset(doc->getType().getField("strwset").getDataType()); @@ -237,8 +232,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyRemoveMultiWset) TEST_F(FieldPathUpdateTestCase, testApplyAssignSingle) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::drekka:karsk")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::drekka:karsk")); EXPECT_TRUE(doc->hasValue("strfoo") == false); // Test assignment of non-existing DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); @@ -255,8 +249,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignSingle) TEST_F(FieldPathUpdateTestCase, testApplyAssignMath) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bat:man")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bat:man")); doc->setValue("num", IntFieldValue(34)); DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); @@ -267,8 +260,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignMath) TEST_F(FieldPathUpdateTestCase, testApplyAssignMathByteToZero) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bat:man")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bat:man")); doc->setValue("byteval", ByteFieldValue(3)); DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); @@ -280,8 +272,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignMathByteToZero) TEST_F(FieldPathUpdateTestCase, testApplyAssignMathNotModifiedOnUnderflow) { int low_value = -126; - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bat:man")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bat:man")); doc->setValue("byteval", ByteFieldValue(low_value)); DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); @@ -293,8 +284,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignMathNotModifiedOnUnderflow) TEST_F(FieldPathUpdateTestCase, testApplyAssignMathNotModifiedOnOverflow) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bat:man")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bat:man")); doc->setValue("byteval", ByteFieldValue(127)); DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); @@ -306,8 +296,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignMathNotModifiedOnOverflow) TEST_F(FieldPathUpdateTestCase, testApplyAssignMathDivZero) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bat:man")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bat:man")); EXPECT_TRUE(doc->hasValue("num") == false); doc->setValue("num", IntFieldValue(10)); @@ -319,8 +308,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignMathDivZero) TEST_F(FieldPathUpdateTestCase, testApplyAssignFieldNotExistingInExpression) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bat:man")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bat:man")); EXPECT_TRUE(doc->hasValue("num") == false); doc->setValue("num", IntFieldValue(10)); @@ -332,8 +320,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignFieldNotExistingInExpression) TEST_F(FieldPathUpdateTestCase, testApplyAssignFieldNotExistingInPath) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bat:man")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bat:man")); DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); try { @@ -346,8 +333,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignFieldNotExistingInPath) TEST_F(FieldPathUpdateTestCase, testApplyAssignTargetNotExisting) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bat:man")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bat:man")); EXPECT_TRUE(doc->hasValue("num") == false); DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); @@ -358,8 +344,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignTargetNotExisting) TEST_F(FieldPathUpdateTestCase, testAssignSimpleMapValueWithVariable) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bug:hunter")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bug:hunter")); MapFieldValue mfv(doc->getType().getField("strmap").getDataType()); mfv.put(StringFieldValue("foo"), StringFieldValue("bar")); @@ -385,8 +370,7 @@ TEST_F(FieldPathUpdateTestCase, testAssignSimpleMapValueWithVariable) TEST_F(FieldPathUpdateTestCase, testApplyAssignMathRemoveIfZero) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bat:man")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bat:man")); EXPECT_TRUE(doc->hasValue("num") == false); doc->setValue("num", IntFieldValue(34)); EXPECT_TRUE(doc->hasValue("num") == true); @@ -402,8 +386,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignMathRemoveIfZero) TEST_F(FieldPathUpdateTestCase, testApplyAssignMultiList) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::fest:skinnvest")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::fest:skinnvest")); EXPECT_TRUE(doc->hasValue("strarray") == false); { @@ -432,8 +415,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignMultiList) TEST_F(FieldPathUpdateTestCase, testApplyAssignMultiWset) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::fest:skinnvest")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::fest:skinnvest")); EXPECT_TRUE(doc->hasValue("strarray") == false); { @@ -463,8 +445,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAssignMultiWset) TEST_F(FieldPathUpdateTestCase, testAssignWsetRemoveIfZero) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::tronder:bataljon")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::tronder:bataljon")); EXPECT_TRUE(doc->hasValue("strarray") == false); { @@ -493,8 +474,7 @@ TEST_F(FieldPathUpdateTestCase, testAssignWsetRemoveIfZero) TEST_F(FieldPathUpdateTestCase, testApplyAddMultiList) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::george:costanza")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::george:costanza")); EXPECT_TRUE(doc->hasValue("strarray") == false); auto adds = std::make_unique<ArrayFieldValue>(doc->getType().getField("strarray").getDataType()); @@ -512,8 +492,7 @@ TEST_F(FieldPathUpdateTestCase, testApplyAddMultiList) TEST_F(FieldPathUpdateTestCase, testAddAndAssignList) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::fancy:pants")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::fancy:pants")); EXPECT_TRUE(doc->hasValue("strarray") == false); { @@ -580,14 +559,12 @@ struct Fixture { Fixture::~Fixture() = default; Fixture::Fixture(const DocumentTypeRepo &repo, const DocumentType &doc_type, const Keys &k) : _doc_type(&doc_type), - doc(new Document(doc_type, DocumentId("id:ns:" + doc_type.getName() + "::planet:express"))), + doc(new Document(repo, doc_type, DocumentId("id:ns:" + doc_type.getName() + "::planet:express"))), mfv(getMapType(doc_type)), fv1(getMapType(doc_type).getValueType()), fv2(getMapType(doc_type).getValueType()), fv3(getMapType(doc_type).getValueType()) { - doc->setRepo(repo); - fv1.setValue("title", StringFieldValue("fry")); fv1.setValue("rating", IntFieldValue(30)); mfv.put(StringFieldValue(k.key1), fv1); @@ -646,7 +623,6 @@ TEST_F(FieldPathUpdateTestCase, testAssignMapStructVariable) DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); docUp.addFieldPathUpdate(std::make_unique<AssignFieldPathUpdate>(*f.doc->getDataType(), "structmap{$x}.rating", "foobar.structmap{$x}.title == \"farnsworth\"", IntFieldValue::make(48))); - f.doc->setRepo(*_repo); docUp.applyTo(*f.doc); std::unique_ptr<MapFieldValue> valueNow = f.doc->getAs<MapFieldValue>(f.doc->getField("structmap")); @@ -665,8 +641,7 @@ createFry(const DataType & type) { } TEST_F(FieldPathUpdateTestCase, testAssignMapNoExist) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::planet:express")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::planet:express")); MapFieldValue mfv(doc->getType().getField("structmap").getDataType()); DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); @@ -683,8 +658,7 @@ TEST_F(FieldPathUpdateTestCase, testAssignMapNoExist) TEST_F(FieldPathUpdateTestCase, testAssignMapNoExistNoCreate) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::planet:express")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::planet:express")); MapFieldValue mfv(doc->getType().getField("structmap").getDataType()); DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); @@ -730,8 +704,7 @@ createTastyCake(const DataType &type) { } TEST_F(FieldPathUpdateTestCase, testEqualityComparison) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::foo:zoo")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::foo:zoo")); MapFieldValue mfv(doc->getType().getField("structmap").getDataType()); { @@ -772,8 +745,7 @@ TEST_F(FieldPathUpdateTestCase, testEqualityComparison) TEST_F(FieldPathUpdateTestCase, testAffectsDocumentBody) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::things:stuff")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::things:stuff")); MapFieldValue mfv(doc->getType().getField("structmap").getDataType()); auto fv4 = std::make_unique<StructFieldValue>(dynamic_cast<const MapDataType&>(*mfv.getDataType()).getValueType()); @@ -801,8 +773,7 @@ TEST_F(FieldPathUpdateTestCase, testAffectsDocumentBody) TEST_F(FieldPathUpdateTestCase, testIncompatibleDataTypeFails) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::things:stuff")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::things:stuff")); MapFieldValue mfv(doc->getType().getField("structmap").getDataType()); DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); @@ -817,8 +788,7 @@ TEST_F(FieldPathUpdateTestCase, testIncompatibleDataTypeFails) TEST_F(FieldPathUpdateTestCase, testSerializeAssign) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::weloveto:serializestuff")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::weloveto:serializestuff")); MapFieldValue mfv(doc->getType().getField("structmap").getDataType()); auto val = std::make_unique<StructFieldValue>(dynamic_cast<const MapDataType&>(*mfv.getDataType()).getValueType()); @@ -836,8 +806,7 @@ TEST_F(FieldPathUpdateTestCase, testSerializeAssign) TEST_F(FieldPathUpdateTestCase, testSerializeAdd) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::george:costanza")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::george:costanza")); EXPECT_TRUE(doc->hasValue("strarray") == false); auto adds = std::make_unique<ArrayFieldValue>(doc->getType().getField("strarray").getDataType()); @@ -854,8 +823,7 @@ TEST_F(FieldPathUpdateTestCase, testSerializeAdd) TEST_F(FieldPathUpdateTestCase, testSerializeRemove) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::weloveto:serializestuff")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::weloveto:serializestuff")); MapFieldValue mfv(doc->getType().getField("structmap").getDataType()); DocumentUpdate docUp(*_repo, *_foobar_type, DocumentId("id:ns:foobar::barbar:foofoo")); @@ -867,8 +835,7 @@ TEST_F(FieldPathUpdateTestCase, testSerializeRemove) TEST_F(FieldPathUpdateTestCase, testSerializeAssignMath) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id:ns:foobar::bat:man")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id:ns:foobar::bat:man")); EXPECT_TRUE(doc->hasValue("num") == false); doc->setValue("num", IntFieldValue(34)); @@ -940,8 +907,7 @@ TEST_F(FieldPathUpdateTestCase, testGenerateSerializedFile) TEST_F(FieldPathUpdateTestCase, array_element_update_for_invalid_index_is_ignored) { - auto doc = std::make_unique<Document>(*_foobar_type, DocumentId("id::foobar::1")); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, DocumentId("id::foobar::1")); auto& field = doc->getType().getField("strarray"); ArrayFieldValue str_array(field.getDataType()); @@ -959,8 +925,7 @@ TEST_F(FieldPathUpdateTestCase, array_element_update_for_invalid_index_is_ignore TEST_F(FieldPathUpdateTestCase, update_can_have_removes_for_both_existent_and_nonexistent_keys) { DocumentId doc_id("id:ns:foobar::george:costanza"); - auto doc = std::make_unique<Document>(*_foobar_type, doc_id); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_foobar_type, doc_id); auto& map_type = dynamic_cast<const MapDataType&>(doc->getType().getField("structmap").getDataType()); auto& struct_type = map_type.getValueType(); MapFieldValue mfv(map_type); diff --git a/document/src/tests/fieldsettest.cpp b/document/src/tests/fieldsettest.cpp index 4ce8e53ae3c..1664ad8e0ff 100644 --- a/document/src/tests/fieldsettest.cpp +++ b/document/src/tests/fieldsettest.cpp @@ -144,7 +144,7 @@ FieldSetTest::doCopyFields(const Document& src, const std::string& fieldSetStr, Document* dest) { - Document destDoc(src.getType(), DocumentId("id:ns:" + src.getType().getName() + "::fieldset")); + Document destDoc(docRepo, src.getType(), DocumentId("id:ns:" + src.getType().getName() + "::fieldset")); if (!dest) { dest = &destDoc; } @@ -196,7 +196,7 @@ TEST_F(FieldSetTest, testCopyDocumentFields) doCopyFields(*src, repo, "testdoctype1:hstringval,content")); // Test that we overwrite already set fields in destination document { - Document dest(src->getType(), DocumentId("id:ns:" + src->getType().getName() + "::bar")); + Document dest(repo, src->getType(), DocumentId("id:ns:" + src->getType().getName() + "::bar")); dest.setValue(dest.getField("content"), StringFieldValue("overwriteme")); EXPECT_EQ(std::string("content: megafoo megabar\n"), doCopyFields(*src, repo, src->getType().getName() + ":content", &dest)); @@ -209,7 +209,7 @@ FieldSetTest::doCopyDocument(const Document& src, const std::string& fieldSetStr) { auto fset = FieldSetRepo::parse(docRepo, fieldSetStr); - Document::UP doc(FieldSet::createDocumentSubsetCopy(src, *fset)); + Document::UP doc(FieldSet::createDocumentSubsetCopy(docRepo, src, *fset)); return stringifyFields(*doc); } @@ -221,7 +221,7 @@ TEST_F(FieldSetTest, testDocumentSubsetCopy) Document::UP src(createTestDocument(testDocMan)); { - Document::UP doc(FieldSet::createDocumentSubsetCopy(*src, AllFields())); + Document::UP doc(FieldSet::createDocumentSubsetCopy(repo, *src, AllFields())); // Test that document id and type are copied correctly. EXPECT_TRUE(doc.get()); EXPECT_EQ(src->getId(), doc->getId()); @@ -230,7 +230,7 @@ TEST_F(FieldSetTest, testDocumentSubsetCopy) stringifyFields(*doc)); } { - Document::UP doc(FieldSet::createDocumentSubsetCopy(*src, DocumentOnly())); + Document::UP doc(FieldSet::createDocumentSubsetCopy(repo, *src, DocumentOnly())); // Test that document id and type are copied correctly. EXPECT_TRUE(doc.get()); EXPECT_EQ(src->getId(), doc->getId()); diff --git a/document/src/tests/fieldvalue/document_test.cpp b/document/src/tests/fieldvalue/document_test.cpp index fd277bc2eb4..3efaabb1c2e 100644 --- a/document/src/tests/fieldvalue/document_test.cpp +++ b/document/src/tests/fieldvalue/document_test.cpp @@ -16,9 +16,9 @@ TEST("require that document with id schema 'id' checks type") { const DataType *type = repo.getDocumentType("testdoctype1"); ASSERT_TRUE(type); - Document(*type, DocumentId("id:ns:testdoctype1::")); // Should not throw + Document(repo.getTypeRepo(), *type, DocumentId("id:ns:testdoctype1::")); // Should not throw - EXPECT_EXCEPTION(Document(*type, DocumentId("id:ns:type::")), + EXPECT_EXCEPTION(Document(repo.getTypeRepo(), *type, DocumentId("id:ns:type::")), vespalib::IllegalArgumentException, "testdoctype1 that don't match the id (type type)"); } diff --git a/document/src/tests/select/select_test.cpp b/document/src/tests/select/select_test.cpp index 03bd17d47b5..30128fbea0a 100644 --- a/document/src/tests/select/select_test.cpp +++ b/document/src/tests/select/select_test.cpp @@ -85,7 +85,7 @@ DocumentSelectTest::check_select(const Document& doc, const vespalib::string& ex TEST_F(DocumentSelectTest, check_existing_reference_field) { - auto document = std::make_unique<Document>(*_child_document_type, DocumentId("id::child::0")); + auto document = std::make_unique<Document>(*_repo, *_child_document_type, DocumentId("id::child::0")); document->setFieldValue(_child_ref_field, std::make_unique<ReferenceFieldValue>(_child_ref_field_type, DocumentId("id::parent::1"))); EXPECT_TRUE(document->hasValue(_child_ref_field)); check_select(*document, "child.ref == null", Result::False); @@ -102,7 +102,7 @@ TEST_F(DocumentSelectTest, check_existing_reference_field) TEST_F(DocumentSelectTest, check_missing_reference_field) { - auto document = std::make_unique<Document>(*_child_document_type, DocumentId("id::child::0")); + auto document = std::make_unique<Document>(*_repo, *_child_document_type, DocumentId("id::child::0")); EXPECT_FALSE(document->hasValue(_child_ref_field)); check_select(*document, "child.ref == null", Result::True); check_select(*document, "child.ref != null", Result::False); diff --git a/document/src/tests/serialization/vespadocumentserializer_test.cpp b/document/src/tests/serialization/vespadocumentserializer_test.cpp index 7528878bfb5..e91e38e0fe4 100644 --- a/document/src/tests/serialization/vespadocumentserializer_test.cpp +++ b/document/src/tests/serialization/vespadocumentserializer_test.cpp @@ -515,7 +515,7 @@ TEST("requireThatDocumentCanBeSerialized") { const DocumentType &type = repo.getDocumentType(); DocumentId doc_id("id:ns:" + type.getName() + "::"); - Document value(type, doc_id); + Document value(repo.getDocumentTypeRepo(), type, doc_id); value.setValue(type.getField("header field"), IntFieldValue(42)); value.setValue(type.getField("body field"), StringFieldValue("foobar")); @@ -580,7 +580,7 @@ TEST("requireThatUnmodifiedDocumentRetainsUnknownFieldOnSerialization") { DocumentTypeRepo repo2Fields(builder2.config()); DocumentId doc_id("id:ns:my_doctype::"); - Document value(*repo2Fields.getDocumentType(doc_type_id), doc_id); + Document value(repo2Fields, *repo2Fields.getDocumentType(doc_type_id), doc_id); value.setValue("field1", IntFieldValue(42)); value.setValue("field2", StringFieldValue("megafoo")); @@ -632,12 +632,12 @@ TEST("requireThatDocumentWithDocumentCanBeSerialized") { setSpanTree(str, *tree); const Field str_field("str", *DataType::STRING); - Document inner(*inner_type, DocumentId("id:ns:" + inner_type->getName() + "::")); + Document inner(my_repo, *inner_type, DocumentId("id:ns:" + inner_type->getName() + "::")); inner.setValue(str_field, str); const DocumentType *type = my_repo.getDocumentType(outer_type_id); ASSERT_TRUE(type); DocumentId doc_id("id:ns:" + type->getName() + "::"); - Document value(*type, doc_id); + Document value(my_repo, *type, doc_id); const Field doc_field(inner_name, *inner_type); value.setValue(doc_field, inner); @@ -659,9 +659,10 @@ TEST("requireThatReadDocumentTypeThrowsIfUnknownType") { template <typename FieldValueT> void serializeToFile(FieldValueT &value, const string &file_name, + const DocumentTypeRepo& my_repo, const DocumentType *type, const string &field_name) { DocumentId doc_id("id:test:" + type->getName() + "::foo"); - Document doc(*type, doc_id); + Document doc(my_repo, *type, doc_id); doc.setValue(type->getField(field_name), value); nbostream stream; @@ -675,7 +676,7 @@ void serializeToFile(FieldValueT &value, const string &file_name, void serializeToFile(PredicateFieldValue &value, const string &file_name) { const DocumentType *type = doc_repo.getDocumentType(predicate_doc_type_id); - serializeToFile(value, file_name, type, predicate_field_name); + serializeToFile(value, file_name, doc_repo, type, predicate_field_name); } template <typename FieldValueT> @@ -819,7 +820,7 @@ const DocumentTypeRepo tensor_doc_repo1(getTensorDocTypesConfig("tensor(dimX{})" void serializeToFile(TensorFieldValue &value, const string &file_name) { const DocumentType *type = tensor_doc_repo.getDocumentType(tensor_doc_type_id); - serializeToFile(value, file_name, type, tensor_field_name); + serializeToFile(value, file_name, tensor_doc_repo, type, tensor_field_name); } void deserializeAndCheck(const string &file_name, TensorFieldValue &value) { @@ -870,7 +871,7 @@ TensorDocFixture::TensorDocFixture(const DocumentTypeRepo &docTypeRepo, : _docTypeRepo(docTypeRepo), _docType(_docTypeRepo.getDocumentType(tensor_doc_type_id)), _tensor(std::move(tensor)), - _doc(*_docType, DocumentId("id:test:my_type::foo")), + _doc(_docTypeRepo, *_docType, DocumentId("id:test:my_type::foo")), _blob() { auto fv = _doc.getField(tensor_field_name).createValue(); @@ -963,7 +964,7 @@ struct RefFixture { const string data_dir = TEST_PATH("../../test/resources/reference/"); const string field_name = "ref_field"; serializeToFile(value, data_dir + file_base_name + "__cpp.new", - ref_doc_type, field_name); + fixed_repo.getDocumentTypeRepo(), ref_doc_type, field_name); vespalib::rename(data_dir + file_base_name + "__cpp.new", data_dir + file_base_name + "__cpp"); @@ -999,7 +1000,7 @@ TEST_F("ReferenceFieldValue with ID serialization matches Java", RefFixture) { struct AssociatedDocumentRepoFixture { const DocumentType& doc_type{repo.getDocumentType()}; DocumentId doc_id{"id:ns:" + doc_type.getName() + "::"}; - Document source_doc{doc_type, doc_id}; + Document source_doc{doc_repo, doc_type, doc_id}; std::unique_ptr<Document> roundtrip_serialize_source_document() { nbostream stream; diff --git a/document/src/tests/testxml.cpp b/document/src/tests/testxml.cpp index 5f194661fe5..13024ddb005 100644 --- a/document/src/tests/testxml.cpp +++ b/document/src/tests/testxml.cpp @@ -22,8 +22,7 @@ namespace { Document::UP createTestDocument(const DocumentTypeRepo& repo) { const DocumentType* type(repo.getDocumentType("testdoc")); - auto doc = std::make_unique<Document>(*type,DocumentId("id:ns:testdoc::crawler/http://www.ntnu.no/")); - doc->setRepo(repo); + auto doc = std::make_unique<Document>(repo, *type, DocumentId("id:ns:testdoc::crawler/http://www.ntnu.no/")); std::string s("humlepungens buffer"); ByteBuffer bb(s.c_str(), s.size()); @@ -45,7 +44,7 @@ Document::UP createTestDocument(const DocumentTypeRepo& repo) val.add(rawVal3); doc->setValue(doc->getField("rawarrayattr"), val); - auto doc2 = std::make_unique<Document>(*type, DocumentId("id:ns:testdoc::crawler/http://www.ntnu.no/2")); + auto doc2 = std::make_unique<Document>(repo, *type, DocumentId("id:ns:testdoc::crawler/http://www.ntnu.no/2")); doc2->setValue(doc2->getField("stringattr"), StringFieldValue("tjo hei paa du")); doc->setValue(doc->getField("docfield"), *doc2); diff --git a/document/src/vespa/document/base/forcelink.cpp b/document/src/vespa/document/base/forcelink.cpp index cfa3354f5f2..975fca5aa2c 100644 --- a/document/src/vespa/document/base/forcelink.cpp +++ b/document/src/vespa/document/base/forcelink.cpp @@ -1,9 +1,10 @@ // Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root. #include "forcelink.h" -#include <vespa/document/update/updates.h> -#include <vespa/document/fieldvalue/fieldvalues.h> #include <vespa/document/datatype/documenttype.h> +#include <vespa/document/fieldvalue/fieldvalues.h> +#include <vespa/document/repo/documenttyperepo.h> +#include <vespa/document/update/updates.h> namespace document { @@ -12,7 +13,8 @@ ForceLink::ForceLink(void) { if (time(NULL) == 0) { DocumentType type("foo", 1); - Document document(type, DocumentId("doc:ns:bar")); + DocumentTypeRepo repo(type); + Document document(repo, *repo.getDocumentType("foo"), DocumentId("doc:ns:bar")); DocumentUpdate documentUpdate; MapValueUpdate mapValueUpdate(std::make_unique<IntFieldValue>(3), std::make_unique<ClearValueUpdate>()); AddValueUpdate addValueUpdate(std::make_unique<IntFieldValue>(3)); diff --git a/document/src/vespa/document/base/testdocman.cpp b/document/src/vespa/document/base/testdocman.cpp index 59e4d4d8386..471a2f8c196 100644 --- a/document/src/vespa/document/base/testdocman.cpp +++ b/document/src/vespa/document/base/testdocman.cpp @@ -79,7 +79,7 @@ TestDocMan::createDocument( { const DocumentType *type_ptr = _repo->getDocumentType(type); assert(type_ptr); - Document::UP doc(new Document(*type_ptr, DocumentId(id))); + Document::UP doc(new Document(*_repo, *type_ptr, DocumentId(id))); doc->setValue(doc->getField("content"), StringFieldValue(content.c_str())); return doc; } diff --git a/document/src/vespa/document/datatype/documenttype.cpp b/document/src/vespa/document/datatype/documenttype.cpp index 0d38ce1f623..80181a7ad35 100644 --- a/document/src/vespa/document/datatype/documenttype.cpp +++ b/document/src/vespa/document/datatype/documenttype.cpp @@ -175,7 +175,7 @@ DocumentType::isA(const DataType& other) const FieldValue::UP DocumentType::createFieldValue() const { - return std::make_unique<Document>(*this, DocumentId("id::" + getName() + "::")); + return Document::make_without_repo(*this, DocumentId("id::" + getName() + "::")); } void diff --git a/document/src/vespa/document/fieldset/fieldset.h b/document/src/vespa/document/fieldset/fieldset.h index 1f53f7a3456..5b67701e395 100644 --- a/document/src/vespa/document/fieldset/fieldset.h +++ b/document/src/vespa/document/fieldset/fieldset.h @@ -6,6 +6,7 @@ namespace document { class Document; +class DocumentTypeRepo; /** * FieldSet class. Represents a subset of fields in a document type. @@ -57,7 +58,7 @@ public: * See comment for copyFields() for performance notes. * @return The new, (partially) copied document instance. */ - static std::unique_ptr<Document> createDocumentSubsetCopy(const Document& src, const FieldSet& fields); + static std::unique_ptr<Document> createDocumentSubsetCopy(const DocumentTypeRepo& type_repo, const Document& src, const FieldSet& fields); /** * Strip all fields _except_ the ones that are contained within the diff --git a/document/src/vespa/document/fieldset/fieldsets.cpp b/document/src/vespa/document/fieldset/fieldsets.cpp index 0ed9ace7467..0ab959d6815 100644 --- a/document/src/vespa/document/fieldset/fieldsets.cpp +++ b/document/src/vespa/document/fieldset/fieldsets.cpp @@ -80,9 +80,9 @@ FieldSet::copyFields(Document& dest, const Document& src, const FieldSet& fields } Document::UP -FieldSet::createDocumentSubsetCopy(const Document& src, const FieldSet& fields) +FieldSet::createDocumentSubsetCopy(const DocumentTypeRepo& type_repo, const Document& src, const FieldSet& fields) { - auto ret = std::make_unique<Document>(src.getType(), src.getId()); + auto ret = std::make_unique<Document>(type_repo, src.getType(), src.getId()); copyFields(*ret, src, fields); return ret; } diff --git a/document/src/vespa/document/fieldvalue/document.cpp b/document/src/vespa/document/fieldvalue/document.cpp index 33b1bbe8d2c..2fb1611f6ff 100644 --- a/document/src/vespa/document/fieldvalue/document.cpp +++ b/document/src/vespa/document/fieldvalue/document.cpp @@ -95,6 +95,26 @@ Document::Document(const DataType &type, DocumentId documentId) } } +Document::UP +Document::make_without_repo(const DataType& type, DocumentId id) +{ + // Must use new as the constructor is private. + return Document::UP(new Document(type, id)); +} + +Document::Document(const DocumentTypeRepo& repo, const DataType &type, DocumentId documentId) + : StructuredFieldValue(Type::DOCUMENT, verifyDocumentType(&type)), + _id(std::move(documentId)), + _fields(repo, getType().getFieldsType()), + _backingBuffer(), + _lastModified(0) +{ + _fields.setDocumentType(getType()); + if (_id.hasDocType() && (_id.getDocType() != type.getName())) { + throwTypeMismatch(type.getName(), _id.getDocType()); + } +} + void Document::setRepo(const DocumentTypeRepo& repo) { _fields.setRepo(repo); diff --git a/document/src/vespa/document/fieldvalue/document.h b/document/src/vespa/document/fieldvalue/document.h index c871e324f05..ac3963a4cc0 100644 --- a/document/src/vespa/document/fieldvalue/document.h +++ b/document/src/vespa/document/fieldvalue/document.h @@ -50,7 +50,13 @@ public: Document(Document &&) noexcept; Document & operator =(const Document &); Document & operator =(Document &&) noexcept; +private: Document(const DataType &, DocumentId id); +public: + // Should preferably only be used by unit tests. + // TODO: Remove all usage of this outside of unit tests. + static Document::UP make_without_repo(const DataType& type, DocumentId id); + Document(const DocumentTypeRepo& repo, const DataType&, DocumentId id); Document(const DocumentTypeRepo& repo, vespalib::nbostream& stream); Document(const DocumentTypeRepo& repo, vespalib::DataBuffer && buffer); ~Document() noexcept override; diff --git a/document/src/vespa/document/fieldvalue/structfieldvalue.cpp b/document/src/vespa/document/fieldvalue/structfieldvalue.cpp index 444e763c52b..083012a213c 100644 --- a/document/src/vespa/document/fieldvalue/structfieldvalue.cpp +++ b/document/src/vespa/document/fieldvalue/structfieldvalue.cpp @@ -36,6 +36,16 @@ StructFieldValue::StructFieldValue(const DataType &type) { } +StructFieldValue::StructFieldValue(const DocumentTypeRepo& repo, const DataType& type) + : StructuredFieldValue(Type::STRUCT, type), + _fields(), + _repo(&repo), + _doc_type(nullptr), + _version(Document::getNewestSerializationVersion()), + _hasChanged(true) +{ +} + StructFieldValue::StructFieldValue(const StructFieldValue & rhs) = default; StructFieldValue & StructFieldValue::operator = (const StructFieldValue & rhs) = default; diff --git a/document/src/vespa/document/fieldvalue/structfieldvalue.h b/document/src/vespa/document/fieldvalue/structfieldvalue.h index 360aa6dca63..e888847fdfe 100644 --- a/document/src/vespa/document/fieldvalue/structfieldvalue.h +++ b/document/src/vespa/document/fieldvalue/structfieldvalue.h @@ -36,6 +36,7 @@ public: using UP = std::unique_ptr<StructFieldValue>; explicit StructFieldValue(const DataType &type); + explicit StructFieldValue(const DocumentTypeRepo& repo, const DataType& type); StructFieldValue(const StructFieldValue & rhs); StructFieldValue & operator = (const StructFieldValue & rhs); StructFieldValue(StructFieldValue && rhs) noexcept = default; diff --git a/documentapi/src/tests/messages/messages60test.cpp b/documentapi/src/tests/messages/messages60test.cpp index ab300794307..258e8821e0c 100644 --- a/documentapi/src/tests/messages/messages60test.cpp +++ b/documentapi/src/tests/messages/messages60test.cpp @@ -79,9 +79,9 @@ namespace { document::Document::SP createDoc(const DocumentTypeRepo &repo, const string &type_name, const string &id) { - return document::Document::SP(new document::Document( + return std::make_shared<document::Document>(repo, *repo.getDocumentType(type_name), - document::DocumentId(id))); + document::DocumentId(id)); } } // namespace diff --git a/documentapi/src/tests/policies/policies_test.cpp b/documentapi/src/tests/policies/policies_test.cpp index 33823681765..ada3e9154f2 100644 --- a/documentapi/src/tests/policies/policies_test.cpp +++ b/documentapi/src/tests/policies/policies_test.cpp @@ -58,6 +58,9 @@ private: static void assertMirrorReady(const IMirrorAPI &mirror); static void assertMirrorContains(const IMirrorAPI &mirror, const string &pattern, uint32_t numEntries); mbus::Message::UP newPutDocumentMessage(const string &documentId); + std::shared_ptr<Document> make_doc(DocumentId docid) { + return std::make_shared<Document>(*_repo, *_docType, docid); + } public: Test(); @@ -169,7 +172,7 @@ void Test::testAND() { TestFrame frame(_repo); - frame.setMessage(make_unique<PutDocumentMessage>(make_shared<Document>(*_docType, DocumentId("id:ns:testdoc::")))); + frame.setMessage(make_unique<PutDocumentMessage>(make_doc(DocumentId("id:ns:testdoc::")))); frame.setHop(mbus::HopSpec("test", "[AND]") .addRecipient("foo") .addRecipient("bar")); @@ -255,7 +258,7 @@ Test::requireThatExternPolicyMergesOneReplyAsProtocol() mbus::Message::UP Test::newPutDocumentMessage(const string &documentId) { - return make_unique<PutDocumentMessage>(std::make_shared<Document>(*_docType, DocumentId(documentId))); + return make_unique<PutDocumentMessage>(make_doc(DocumentId(documentId))); } void @@ -389,7 +392,7 @@ Test::testLocalService() { // Prepare message. TestFrame frame(_repo, "docproc/cluster.default"); - frame.setMessage(make_unique<PutDocumentMessage>(make_shared<Document>(*_docType, DocumentId("id:ns:testdoc::")))); + frame.setMessage(make_unique<PutDocumentMessage>(make_doc(DocumentId("id:ns:testdoc::")))); // Test select with proper address. for (uint32_t i = 0; i < 10; ++i) { @@ -470,7 +473,7 @@ Test::testRoundRobin() { // Prepare message. TestFrame frame(_repo, "docproc/cluster.default"); - frame.setMessage(make_unique<PutDocumentMessage>(make_shared<Document>(*_docType, DocumentId("id:ns:testdoc::")))); + frame.setMessage(make_unique<PutDocumentMessage>(make_doc(DocumentId("id:ns:testdoc::")))); // Test select with proper address. for (uint32_t i = 0; i < 10; ++i) { @@ -562,7 +565,7 @@ Test::multipleGetRepliesAreMergedToFoundDocument() for (uint32_t i = 0, len = selected.size(); i < len; ++i) { Document::SP doc; if (i == 0) { - doc = std::make_shared<Document>(*_docType, DocumentId("id:ns:testdoc::yarn")); + doc = make_doc(DocumentId("id:ns:testdoc::yarn")); doc->setLastModified(123456ULL); } auto reply = std::make_unique<GetDocumentReply>(std::move(doc)); @@ -611,7 +614,7 @@ Test::testDocumentRouteSelector() frame.setMessage(make_unique<GetDocumentMessage>(DocumentId("id:ns:testdoc::"))); EXPECT_TRUE(frame.testSelect(StringList().add("foo"))); - mbus::Message::UP put = make_unique<PutDocumentMessage>(make_shared<Document>(*_docType, DocumentId("id:ns:testdoc::"))); + mbus::Message::UP put = make_unique<PutDocumentMessage>(make_doc(DocumentId("id:ns:testdoc::"))); frame.setMessage(std::move(put)); EXPECT_TRUE(frame.testSelect( StringList().add("foo"))); @@ -622,7 +625,7 @@ Test::testDocumentRouteSelector() make_shared<DocumentUpdate>(*_repo, *_docType, DocumentId("id:ns:testdoc::")))); EXPECT_TRUE(frame.testSelect(StringList().add("foo"))); - put = make_unique<PutDocumentMessage>(make_shared<Document>(*_docType, DocumentId("id:ns:testdoc::"))); + put = make_unique<PutDocumentMessage>(make_doc(DocumentId("id:ns:testdoc::"))); frame.setMessage(std::move(put)); EXPECT_TRUE(frame.testMergeOneReply("foo")); } @@ -639,7 +642,7 @@ Test::testDocumentRouteSelectorIgnore() .addRecipient("docproc/cluster.foo")); frame.setMessage(make_unique<PutDocumentMessage>( - make_shared<Document>(*_docType, DocumentId("id:yarn:testdoc:n=1234:fluff")))); + make_doc(DocumentId("id:yarn:testdoc:n=1234:fluff")))); std::vector<mbus::RoutingNode*> leaf; ASSERT_TRUE(frame.select(leaf, 0)); mbus::Reply::UP reply = frame.getReceptor().getReply(TIMEOUT); @@ -912,7 +915,7 @@ Test::testSubsetService() { // Prepare message. TestFrame frame(_repo, "docproc/cluster.default"); - frame.setMessage(make_unique<PutDocumentMessage>(make_shared<Document>(*_docType, DocumentId("id:ns:testdoc::")))); + frame.setMessage(make_unique<PutDocumentMessage>(make_doc(DocumentId("id:ns:testdoc::")))); // Test requerying for adding nodes. frame.setHop(mbus::HopSpec("test", "docproc/cluster.default/[SubsetService:2]/chain.default")); diff --git a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java index 8b7a2bafc40..fa9cfff0d68 100644 --- a/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java +++ b/node-repository/src/main/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsResponse.java @@ -120,11 +120,13 @@ public class MetricsResponse { cpu { // a node resource @Override - public List<String> metricResponseNames() { return List.of(HostedNodeAdminMetrics.CPU_UTIL.baseName()); } + public List<String> metricResponseNames() { + return List.of(HostedNodeAdminMetrics.CPU_UTIL.baseName(), HostedNodeAdminMetrics.GPU_UTIL.baseName()); + } @Override double computeFinal(ListMap<String, Double> values) { - return values.values().stream().flatMap(List::stream).mapToDouble(v -> v).average().orElse(0) / 100; // % to ratio + return values.values().stream().flatMap(List::stream).mapToDouble(v -> v).max().orElse(0) / 100; // % to ratio } }, @@ -133,11 +135,17 @@ public class MetricsResponse { @Override public List<String> metricResponseNames() { return List.of(HostedNodeAdminMetrics.MEM_UTIL.baseName(), - SearchNodeMetrics.CONTENT_PROTON_RESOURCE_USAGE_MEMORY.average()); + SearchNodeMetrics.CONTENT_PROTON_RESOURCE_USAGE_MEMORY.average(), + HostedNodeAdminMetrics.GPU_MEM_USED.baseName(), + HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()); } @Override double computeFinal(ListMap<String, Double> values) { + return Math.max(gpuMemUtil(values), cpuMemUtil(values)); + } + + private double cpuMemUtil(ListMap<String, Double> values) { var valueList = values.get(SearchNodeMetrics.CONTENT_PROTON_RESOURCE_USAGE_MEMORY.average()); // prefer over mem.util if ( ! valueList.isEmpty()) return valueList.get(0); @@ -147,6 +155,12 @@ public class MetricsResponse { return 0; } + private double gpuMemUtil(ListMap<String, Double> values) { + var usedGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_USED.baseName()).stream().mapToDouble(v -> v).sum(); + var totalGpuMemory = values.get(HostedNodeAdminMetrics.GPU_MEM_TOTAL.baseName()).stream().mapToDouble(v -> v).sum(); + return totalGpuMemory > 0 ? usedGpuMemory / totalGpuMemory : 0; + } + }, disk { // a node resource diff --git a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java index 24697d02681..01a4e96a195 100644 --- a/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java +++ b/node-repository/src/test/java/com/yahoo/vespa/hosted/provision/autoscale/MetricsV2MetricsFetcherTest.java @@ -80,7 +80,7 @@ public class MetricsV2MetricsFetcherTest { assertTrue(values.get(0).getSecond().stable()); } - { + { // read response 2 when unstable httpClient.cannedResponse = cannedResponseForApplication2; try (Mutex lock = tester.nodeRepository().applications().lock(application1)) { tester.nodeRepository().nodes().write(tester.nodeRepository().nodes().list(Node.State.active).owner(application2) @@ -89,6 +89,18 @@ public class MetricsV2MetricsFetcherTest { List<Pair<String, NodeMetricSnapshot>> values = new ArrayList<>(fetcher.fetchMetrics(application2).get().nodeMetrics()); assertFalse(values.get(0).getSecond().stable()); } + + { + httpClient.cannedResponse = cannedResponseForApplication3; + List<Pair<String, NodeMetricSnapshot>> values = new ArrayList<>(fetcher.fetchMetrics(application2).get().nodeMetrics()); + assertEquals("http://host-3.yahoo.com:4080/metrics/v2/values?consumer=autoscaling", + httpClient.requestsReceived.get(1)); + assertEquals(1, values.size()); + assertEquals("host-3.yahoo.com", values.get(0).getFirst()); + assertEquals(0.13, values.get(0).getSecond().load().cpu(), delta); + assertEquals(0.9375, values.get(0).getSecond().load().memory(), delta); + } + } private static class MockHttpClient implements MetricsV2MetricsFetcher.AsyncHttpClient { @@ -208,7 +220,42 @@ public class MetricsV2MetricsFetcherTest { { "values": { "cpu.util": 10, + "gpu.util": 8, + "mem.util": 15, + "gpu.memory.used": 0, + "gpu.memory.total": 8, + "disk.util": 20, + "application_generation.last": 3, + "in_service.last": 0 + }, + "dimensions": { + "state": "active" + } + } + ] + } + } + ] + } + """; + + final String cannedResponseForApplication3 = + """ + { + "nodes": [ + { + "hostname": "host-3.yahoo.com", + "role": "role0", + "node": { + "timestamp": 1300, + "metrics": [ + { + "values": { + "cpu.util": 10, + "gpu.util": 13, "mem.util": 15, + "gpu.memory.used": 7.5, + "gpu.memory.total": 8, "disk.util": 20, "application_generation.last": 3, "in_service.last": 0 diff --git a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp index 0c0086861b2..993a8baec09 100644 --- a/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp +++ b/persistence/src/vespa/persistence/dummyimpl/dummypersistence.cpp @@ -477,7 +477,7 @@ DummyPersistence::updateAsync(const Bucket& bucket, Timestamp ts, DocumentUpdate onComplete->onComplete(std::make_unique<UpdateResult>()); return; } else { - docToUpdate = std::make_shared<document::Document>(upd->getType(), upd->getId()); + docToUpdate = std::make_shared<document::Document>(*upd->getRepoPtr(), upd->getType(), upd->getId()); updatedTs = ts; } } @@ -680,7 +680,7 @@ DummyPersistence::iterate(IteratorId id, uint64_t maxByteSize) const { assert(entry->getDocument()); // Create new document with only wanted fields. - Document::UP filtered(FieldSet::createDocumentSubsetCopy(*entry->getDocument(), *it->_fieldSet)); + auto filtered = FieldSet::createDocumentSubsetCopy(*_repo, *entry->getDocument(), *it->_fieldSet); auto ret = DocEntry::create(entry->getTimestamp(), std::move(filtered), entry->getSize()); entries.push_back(std::move(ret)); } else { diff --git a/searchcore/src/tests/proton/attribute/attribute_populator/attribute_populator_test.cpp b/searchcore/src/tests/proton/attribute/attribute_populator/attribute_populator_test.cpp index 19b8348fb7a..b4d3eb13ac7 100644 --- a/searchcore/src/tests/proton/attribute/attribute_populator/attribute_populator_test.cpp +++ b/searchcore/src/tests/proton/attribute/attribute_populator/attribute_populator_test.cpp @@ -60,7 +60,7 @@ struct DocContext std::shared_ptr<Document> create(uint32_t id, int64_t fieldValue) { vespalib::string docId = vespalib::make_string("id:searchdocument:searchdocument::%u", id); - auto doc = std::make_shared<Document>(*_repo->getDocumentType("searchdocument"), DocumentId(docId)); + auto doc = std::make_shared<Document>(*_repo, *_repo->getDocumentType("searchdocument"), DocumentId(docId)); doc->setValue("a1", IntFieldValue(fieldValue)); return doc; } diff --git a/searchcore/src/tests/proton/attribute/attribute_test.cpp b/searchcore/src/tests/proton/attribute/attribute_test.cpp index 75d9c78d07e..4458cd66ad6 100644 --- a/searchcore/src/tests/proton/attribute/attribute_test.cpp +++ b/searchcore/src/tests/proton/attribute/attribute_test.cpp @@ -1050,7 +1050,7 @@ public: } std::unique_ptr<Document> makeDoc() { - return std::make_unique<Document>(_type, DocumentId("id::test::1")); + return Document::make_without_repo(_type, DocumentId("id::test::1")); } }; diff --git a/searchcore/src/tests/proton/attribute/document_field_extractor/document_field_extractor_test.cpp b/searchcore/src/tests/proton/attribute/document_field_extractor/document_field_extractor_test.cpp index 903b4d89696..42dad54394f 100644 --- a/searchcore/src/tests/proton/attribute/document_field_extractor/document_field_extractor_test.cpp +++ b/searchcore/src/tests/proton/attribute/document_field_extractor/document_field_extractor_test.cpp @@ -109,7 +109,7 @@ struct FixtureBase Document * makeDoc() { - doc = std::make_unique<Document>(type, DocumentId("id::test::1")); + doc = Document::make_without_repo(type, DocumentId("id::test::1")); extractor = std::make_unique<DocumentFieldExtractor>(*doc); return doc.get(); } diff --git a/searchcore/src/tests/proton/common/cachedselect_test.cpp b/searchcore/src/tests/proton/common/cachedselect_test.cpp index 6565ec601e6..93a7e46285e 100644 --- a/searchcore/src/tests/proton/common/cachedselect_test.cpp +++ b/searchcore/src/tests/proton/common/cachedselect_test.cpp @@ -123,7 +123,7 @@ makeDoc(const DocumentTypeRepo &repo, int32_t ab) { const DocumentType *docType = repo.getDocumentType("test"); - Document::UP doc(new Document(*docType, DocumentId(docId))); + auto doc = std::make_unique<Document>(repo, *docType, DocumentId(docId)); if (ia != "null") doc->setValue("ia", StringFieldValue(ia)); if (ib != "null") @@ -348,7 +348,7 @@ TestFixture::testParse(const string &selection, const DocumentType *docType = repo.getDocumentType(docTypeName); ASSERT_TRUE(docType != nullptr); - Document::UP emptyDoc(new Document(*docType, DocumentId())); + auto emptyDoc = std::make_unique<Document>(repo, *docType, DocumentId()); res->set(selection, docTypeName, diff --git a/searchcore/src/tests/proton/common/selectpruner_test.cpp b/searchcore/src/tests/proton/common/selectpruner_test.cpp index 4bc7ef53d94..80d6314c392 100644 --- a/searchcore/src/tests/proton/common/selectpruner_test.cpp +++ b/searchcore/src/tests/proton/common/selectpruner_test.cpp @@ -222,8 +222,7 @@ TestFixture::testPrune(const string &selection, const string &exp, const string LOG(info, "ParseTree: '%s'", os.str().c_str()); const DocumentType *docType = repo.getDocumentType(docTypeName); ASSERT_TRUE(docType != nullptr); - auto emptyDoc = std::make_unique<Document>(*docType, document::DocumentId("id:ns:" + docTypeName + "::1")); - emptyDoc->setRepo(repo); + auto emptyDoc = std::make_unique<Document>(repo, *docType, document::DocumentId("id:ns:" + docTypeName + "::1")); SelectPruner pruner(docTypeName, &_amgr, *emptyDoc, repo, _hasFields, _hasDocuments); pruner.process(*select); std::ostringstream pos; diff --git a/searchcore/src/tests/proton/document_iterator/document_iterator_test.cpp b/searchcore/src/tests/proton/document_iterator/document_iterator_test.cpp index f89af9a11a6..ff55d3cca7c 100644 --- a/searchcore/src/tests/proton/document_iterator/document_iterator_test.cpp +++ b/searchcore/src/tests/proton/document_iterator/document_iterator_test.cpp @@ -156,8 +156,12 @@ struct UnitDR : DocumentRetrieverBaseForTest { static void reset() { _docidCnt = 2; } }; +Document::UP make_doc(DocumentId docid) { + return Document::make_without_repo(*DataType::DOCUMENT, docid); +} + UnitDR::UnitDR() - : repo(), document(std::make_unique<Document>(*DataType::DOCUMENT, DocumentId())), timestamp(0), + : repo(), document(make_doc(DocumentId())), timestamp(0), bucket(), removed(false), docid(0), docIdLimit(std::numeric_limits<uint32_t>::max()) {} UnitDR::UnitDR(document::Document::UP d, Timestamp t, Bucket b, bool r) @@ -242,7 +246,7 @@ struct AttrUnitDR : public UnitDR CachedSelect::SP parseSelect(const vespalib::string &selection) const override { auto res = std::make_shared<CachedSelect>(); - res->set(selection, "foo", Document(document->getType(), DocumentId()), repo, &_amgr, true); + res->set(selection, "foo", Document(repo, document->getType(), DocumentId()), repo, &_amgr, true); return res; } }; @@ -291,7 +295,7 @@ IDocumentRetriever::SP nil() { return std::make_unique<UnitDR>(); } IDocumentRetriever::SP doc(const DocumentId &id, Timestamp t, Bucket b) { - return std::make_shared<UnitDR>(std::make_unique<Document>(*DataType::DOCUMENT, id), t, b, false); + return std::make_shared<UnitDR>(make_doc(id), t, b, false); } IDocumentRetriever::SP @@ -301,7 +305,7 @@ doc(const std::string &id, Timestamp t, Bucket b) { IDocumentRetriever::SP rem(const DocumentId &id, Timestamp t, Bucket b) { - return std::make_shared<UnitDR>(std::make_unique<Document>(*DataType::DOCUMENT, id), t, b, true); + return std::make_shared<UnitDR>(make_doc(id), t, b, true); } IDocumentRetriever::SP @@ -338,14 +342,14 @@ const DocumentType &getAttrDocType() { } IDocumentRetriever::SP doc_with_fields(const std::string &id, Timestamp t, Bucket b) { - auto d = std::make_unique<Document>(getDocType(), DocumentId(id)); + auto d = Document::make_without_repo(getDocType(), DocumentId(id)); d->setValue("header", StringFieldValue::make("foo")); d->setValue("body", StringFieldValue::make("bar")); return std::make_shared<UnitDR>(getDocType(), std::move(d), t, b, false); } IDocumentRetriever::SP doc_with_null_fields(const std::string &id, Timestamp t, Bucket b) { - return std::make_unique<AttrUnitDR>(std::make_unique<Document>(getAttrDocType(), DocumentId(id)), t, b, false); + return std::make_unique<AttrUnitDR>(Document::make_without_repo(getAttrDocType(), DocumentId(id)), t, b, false); } IDocumentRetriever::SP doc_with_attr_fields(const vespalib::string &id, @@ -355,7 +359,7 @@ IDocumentRetriever::SP doc_with_attr_fields(const vespalib::string &id, const vespalib::string &ss, const vespalib::string &attr_ss) { - auto d = std::make_unique<Document>(getAttrDocType(), DocumentId(id)); + auto d = Document::make_without_repo(getAttrDocType(), DocumentId(id)); d->setValue("header", StringFieldValue::make("foo")); d->setValue("body", StringFieldValue::make("bar")); d->setValue("aa", IntFieldValue::make(aa)); @@ -367,7 +371,7 @@ IDocumentRetriever::SP doc_with_attr_fields(const vespalib::string &id, auto doc_rec(VisitRecordingUnitDR::VisitedLIDs& visited_lids, const std::string &id, Timestamp t, Bucket b) { - return std::make_shared<VisitRecordingUnitDR>(visited_lids, std::make_unique<Document>(getAttrDocType(), DocumentId(id)), t, b, false); + return std::make_shared<VisitRecordingUnitDR>(visited_lids, Document::make_without_repo(getAttrDocType(), DocumentId(id)), t, b, false); } void checkDoc(const IDocumentRetriever &dr, const std::string &id, @@ -462,9 +466,9 @@ TEST("require that normal documents can be iterated") { IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(3u, res.getEntries().size()); - TEST_DO(checkEntry(res, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::1")), Timestamp(2))); - TEST_DO(checkEntry(res, 1, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::2")), Timestamp(3))); - TEST_DO(checkEntry(res, 2, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::3")), Timestamp(4))); + TEST_DO(checkEntry(res, 0, *make_doc(DocumentId("id:ns:document::1")), Timestamp(2))); + TEST_DO(checkEntry(res, 1, *make_doc(DocumentId("id:ns:document::2")), Timestamp(3))); + TEST_DO(checkEntry(res, 2, *make_doc(DocumentId("id:ns:document::3")), Timestamp(4))); } void verifyIterateIgnoringStopSignal(DocumentIterator & itr) { @@ -495,7 +499,7 @@ void verifyReadConsistency(DocumentIterator & itr, ILidCommitState & lidCommitSt IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(1u, res.getEntries().size()); - TEST_DO(checkEntry(res, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::1")), Timestamp(2))); + TEST_DO(checkEntry(res, 0, *make_doc(DocumentId("id:ns:document::1")), Timestamp(2))); } class ILidCommitStateProxy : public ILidCommitState { @@ -552,7 +556,7 @@ TEST("require that docid limit is honoured") { IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(1u, res.getEntries().size()); - TEST_DO(checkEntry(res, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::1")), Timestamp(2))); + TEST_DO(checkEntry(res, 0, *make_doc(DocumentId("id:ns:document::1")), Timestamp(2))); udr.setDocIdLimit(7); DocumentIterator limited(bucket(5), std::make_shared<document::AllFields>(), selectAll(), newestV(), -1, false); @@ -583,7 +587,7 @@ TEST("require that remove entries can be ignored") { IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(1u, res.getEntries().size()); - TEST_DO(checkEntry(res, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::2")), Timestamp(3))); + TEST_DO(checkEntry(res, 0, *make_doc(DocumentId("id:ns:document::2")), Timestamp(3))); } TEST("require that iterating all versions returns both documents and removes") { @@ -595,7 +599,7 @@ TEST("require that iterating all versions returns both documents and removes") { EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(3u, res.getEntries().size()); TEST_DO(checkEntry(res, 0, DocumentId("id:ns:document::1"), Timestamp(2))); - TEST_DO(checkEntry(res, 1, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::2")), Timestamp(3))); + TEST_DO(checkEntry(res, 1, *make_doc(DocumentId("id:ns:document::2")), Timestamp(3))); TEST_DO(checkEntry(res, 2, DocumentId("id:ns:document::3"), Timestamp(4))); } @@ -620,7 +624,7 @@ TEST("require that entries in other buckets are skipped") { IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(1u, res.getEntries().size()); - TEST_DO(checkEntry(res, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::2")), Timestamp(3))); + TEST_DO(checkEntry(res, 0, *make_doc(DocumentId("id:ns:document::2")), Timestamp(3))); } TEST("require that maxBytes splits iteration results") { @@ -628,16 +632,16 @@ TEST("require that maxBytes splits iteration results") { itr.add(doc("id:ns:document::1", Timestamp(2), bucket(5))); itr.add(cat(rem("id:ns:document::2", Timestamp(3), bucket(5)), doc("id:ns:document::3", Timestamp(4), bucket(5)))); - IterateResult res1 = itr.iterate(getSize(Document(*DataType::DOCUMENT, DocumentId("id:ns:document::1"))) + + IterateResult res1 = itr.iterate(getSize(*make_doc(DocumentId("id:ns:document::1"))) + getSize(DocumentId("id:ns:document::2"))); EXPECT_TRUE(!res1.isCompleted()); EXPECT_EQUAL(2u, res1.getEntries().size()); - TEST_DO(checkEntry(res1, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::1")), Timestamp(2))); + TEST_DO(checkEntry(res1, 0, *make_doc(DocumentId("id:ns:document::1")), Timestamp(2))); TEST_DO(checkEntry(res1, 1, DocumentId("id:ns:document::2"), Timestamp(3))); IterateResult res2 = itr.iterate(largeNum); EXPECT_TRUE(res2.isCompleted()); - TEST_DO(checkEntry(res2, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::3")), Timestamp(4))); + TEST_DO(checkEntry(res2, 0, *make_doc(DocumentId("id:ns:document::3")), Timestamp(4))); IterateResult res3 = itr.iterate(largeNum); EXPECT_TRUE(res3.isCompleted()); @@ -671,7 +675,7 @@ TEST("require that at least one document is returned by visit") { doc("id:ns:document::3", Timestamp(4), bucket(5)))); IterateResult res1 = itr.iterate(0); EXPECT_TRUE( ! res1.getEntries().empty()); - TEST_DO(checkEntry(res1, 0, Document(*DataType::DOCUMENT,DocumentId("id:ns:document::1")), Timestamp(2))); + TEST_DO(checkEntry(res1, 0, *make_doc(DocumentId("id:ns:document::1")), Timestamp(2))); } TEST("require that documents outside the timestamp limits are ignored") { @@ -687,8 +691,8 @@ TEST("require that documents outside the timestamp limits are ignored") { IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(4u, res.getEntries().size()); - TEST_DO(checkEntry(res, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::2")), Timestamp(100))); - TEST_DO(checkEntry(res, 1, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::3")), Timestamp(200))); + TEST_DO(checkEntry(res, 0, *make_doc(DocumentId("id:ns:document::2")), Timestamp(100))); + TEST_DO(checkEntry(res, 1, *make_doc(DocumentId("id:ns:document::3")), Timestamp(200))); TEST_DO(checkEntry(res, 2, DocumentId("id:ns:document::6"), Timestamp(100))); TEST_DO(checkEntry(res, 3, DocumentId("id:ns:document::7"), Timestamp(200))); } @@ -706,8 +710,8 @@ TEST("require that timestamp subset returns the appropriate documents") { IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(3u, res.getEntries().size()); - TEST_DO(checkEntry(res, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::2")), Timestamp(400))); - TEST_DO(checkEntry(res, 1, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::4")), Timestamp(200))); + TEST_DO(checkEntry(res, 0, *make_doc(DocumentId("id:ns:document::2")), Timestamp(400))); + TEST_DO(checkEntry(res, 1, *make_doc(DocumentId("id:ns:document::4")), Timestamp(200))); TEST_DO(checkEntry(res, 2, DocumentId("id:ns:document::6"), Timestamp(350))); } @@ -724,8 +728,8 @@ TEST("require that document selection will filter results") { IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(4u, res.getEntries().size()); - TEST_DO(checkEntry(res, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::xxx1")), Timestamp(99))); - TEST_DO(checkEntry(res, 1, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::xxx2")), Timestamp(200))); + TEST_DO(checkEntry(res, 0, *make_doc(DocumentId("id:ns:document::xxx1")), Timestamp(99))); + TEST_DO(checkEntry(res, 1, *make_doc(DocumentId("id:ns:document::xxx2")), Timestamp(200))); TEST_DO(checkEntry(res, 2, DocumentId("id:ns:document::xxx3"), Timestamp(99))); TEST_DO(checkEntry(res, 3, DocumentId("id:ns:document::xxx4"), Timestamp(200))); } @@ -737,10 +741,10 @@ TEST("require that document selection handles 'field == null'") { IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); ASSERT_EQUAL(2u, res.getEntries().size()); - Document expected1(getAttrDocType(), DocumentId("id:ns:foo::xxx1")); - TEST_DO(checkEntry(res, 0, expected1, Timestamp(99))); - Document expected2(getAttrDocType(), DocumentId("id:ns:foo::xxx2")); - TEST_DO(checkEntry(res, 1, expected2, Timestamp(100))); + auto expected1 = Document::make_without_repo(getAttrDocType(), DocumentId("id:ns:foo::xxx1")); + TEST_DO(checkEntry(res, 0, *expected1, Timestamp(99))); + auto expected2 = Document::make_without_repo(getAttrDocType(), DocumentId("id:ns:foo::xxx2")); + TEST_DO(checkEntry(res, 1, *expected2, Timestamp(100))); } TEST("require that invalid document selection returns no documents") { @@ -771,7 +775,7 @@ TEST("require that document selection and timestamp range works together") { IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(2u, res.getEntries().size()); - TEST_DO(checkEntry(res, 0, Document(*DataType::DOCUMENT, DocumentId("id:ns:document::xxx2")), Timestamp(200))); + TEST_DO(checkEntry(res, 0, *make_doc(DocumentId("id:ns:document::xxx2")), Timestamp(200))); TEST_DO(checkEntry(res, 1, DocumentId("id:ns:document::xxx4"), Timestamp(200))); } @@ -782,9 +786,9 @@ TEST("require that fieldset limits fields returned") { IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(1u, res.getEntries().size()); - Document expected(getDocType(), DocumentId("id:ns:foo::xxx1")); - expected.setValue("header", StringFieldValue::make("foo")); - TEST_DO(checkEntry(res, 0, expected, Timestamp(1))); + auto expected = Document::make_without_repo(getDocType(), DocumentId("id:ns:foo::xxx1")); + expected->setValue("header", StringFieldValue::make("foo")); + TEST_DO(checkEntry(res, 0, *expected, Timestamp(1))); } namespace { @@ -838,22 +842,22 @@ TEST("require that attributes are used") IterateResult res = itr.iterate(largeNum); EXPECT_TRUE(res.isCompleted()); EXPECT_EQUAL(2u, res.getEntries().size()); - Document expected1(getAttrDocType(), DocumentId("id:ns:foo::xx2")); - expected1.setValue("header", StringFieldValue::make("foo")); - expected1.setValue("body", StringFieldValue::make("bar")); - expected1.setValue("aa", IntFieldValue::make(27)); - expected1.setValue("ab", IntFieldValue::make(28)); - expected1.setValue("dd", DoubleFieldValue::make(2.7)); - expected1.setValue("ss", StringFieldValue::make("x27")); - Document expected2(getAttrDocType(), DocumentId("id:ns:foo::xx4")); - expected2.setValue("header", StringFieldValue::make("foo")); - expected2.setValue("body", StringFieldValue::make("bar")); - expected2.setValue("aa", IntFieldValue::make(45)); - expected2.setValue("ab", IntFieldValue::make(46)); - expected2.setValue("dd", DoubleFieldValue::make(4.5)); - expected2.setValue("ss", StringFieldValue::make("x45")); - TEST_DO(checkEntry(res, 0, expected1, Timestamp(2))); - TEST_DO(checkEntry(res, 1, expected2, Timestamp(4))); + auto expected1 = Document::make_without_repo(getAttrDocType(), DocumentId("id:ns:foo::xx2")); + expected1->setValue("header", StringFieldValue::make("foo")); + expected1->setValue("body", StringFieldValue::make("bar")); + expected1->setValue("aa", IntFieldValue::make(27)); + expected1->setValue("ab", IntFieldValue::make(28)); + expected1->setValue("dd", DoubleFieldValue::make(2.7)); + expected1->setValue("ss", StringFieldValue::make("x27")); + auto expected2 = Document::make_without_repo(getAttrDocType(), DocumentId("id:ns:foo::xx4")); + expected2->setValue("header", StringFieldValue::make("foo")); + expected2->setValue("body", StringFieldValue::make("bar")); + expected2->setValue("aa", IntFieldValue::make(45)); + expected2->setValue("ab", IntFieldValue::make(46)); + expected2->setValue("dd", DoubleFieldValue::make(4.5)); + expected2->setValue("ss", StringFieldValue::make("x45")); + TEST_DO(checkEntry(res, 0, *expected1, Timestamp(2))); + TEST_DO(checkEntry(res, 1, *expected2, Timestamp(4))); DocumentIterator itr2(bucket(5), std::make_shared<document::AllFields>(), selectDocs("foo.dd == 4.5"), docV(), -1, false); itr2.add(doc_with_attr_fields("id:ns:foo::xx5", Timestamp(5), bucket(5), @@ -868,22 +872,22 @@ TEST("require that attributes are used") IterateResult res2 = itr2.iterate(largeNum); EXPECT_TRUE(res2.isCompleted()); EXPECT_EQUAL(2u, res2.getEntries().size()); - Document expected3(getAttrDocType(), DocumentId("id:ns:foo::xx6")); - expected3.setValue("header", StringFieldValue::make("foo")); - expected3.setValue("body", StringFieldValue::make("bar")); - expected3.setValue("aa", IntFieldValue::make(27)); - expected3.setValue("ab", IntFieldValue::make(28)); - expected3.setValue("dd", DoubleFieldValue::make(2.7)); - expected3.setValue("ss", StringFieldValue::make("x27")); - Document expected4(getAttrDocType(), DocumentId("id:ns:foo::xx8")); - expected4.setValue("header", StringFieldValue::make("foo")); - expected4.setValue("body", StringFieldValue::make("bar")); - expected4.setValue("aa", IntFieldValue::make(45)); - expected4.setValue("ab", IntFieldValue::make(46)); - expected4.setValue("dd", DoubleFieldValue::make(4.5)); - expected4.setValue("ss", StringFieldValue::make("x45")); - TEST_DO(checkEntry(res2, 0, expected3, Timestamp(6))); - TEST_DO(checkEntry(res2, 1, expected4, Timestamp(8))); + auto expected3 = Document::make_without_repo(getAttrDocType(), DocumentId("id:ns:foo::xx6")); + expected3->setValue("header", StringFieldValue::make("foo")); + expected3->setValue("body", StringFieldValue::make("bar")); + expected3->setValue("aa", IntFieldValue::make(27)); + expected3->setValue("ab", IntFieldValue::make(28)); + expected3->setValue("dd", DoubleFieldValue::make(2.7)); + expected3->setValue("ss", StringFieldValue::make("x27")); + auto expected4 = Document::make_without_repo(getAttrDocType(), DocumentId("id:ns:foo::xx8")); + expected4->setValue("header", StringFieldValue::make("foo")); + expected4->setValue("body", StringFieldValue::make("bar")); + expected4->setValue("aa", IntFieldValue::make(45)); + expected4->setValue("ab", IntFieldValue::make(46)); + expected4->setValue("dd", DoubleFieldValue::make(4.5)); + expected4->setValue("ss", StringFieldValue::make("x45")); + TEST_DO(checkEntry(res2, 0, *expected3, Timestamp(6))); + TEST_DO(checkEntry(res2, 1, *expected4, Timestamp(8))); DocumentIterator itr3(bucket(5), std::make_shared<document::AllFields>(), selectDocs("foo.ss == \"x45\""), docV(), -1, false); itr3.add(doc_with_attr_fields("id:ns:foo::xx9", Timestamp(9), bucket(5), @@ -898,22 +902,22 @@ TEST("require that attributes are used") IterateResult res3 = itr3.iterate(largeNum); EXPECT_TRUE(res3.isCompleted()); EXPECT_EQUAL(2u, res3.getEntries().size()); - Document expected5(getAttrDocType(), DocumentId("id:ns:foo::xx10")); - expected5.setValue("header", StringFieldValue::make("foo")); - expected5.setValue("body", StringFieldValue::make("bar")); - expected5.setValue("aa", IntFieldValue::make(27)); - expected5.setValue("ab", IntFieldValue::make(28)); - expected5.setValue("dd", DoubleFieldValue::make(2.7)); - expected5.setValue("ss", StringFieldValue::make("x27")); - Document expected6(getAttrDocType(), DocumentId("id:ns:foo::xx12")); - expected6.setValue("header", StringFieldValue::make("foo")); - expected6.setValue("body", StringFieldValue::make("bar")); - expected6.setValue("aa", IntFieldValue::make(45)); - expected6.setValue("ab", IntFieldValue::make(46)); - expected6.setValue("dd", DoubleFieldValue::make(4.5)); - expected6.setValue("ss", StringFieldValue::make("x45")); - TEST_DO(checkEntry(res3, 0, expected5, Timestamp(10))); - TEST_DO(checkEntry(res3, 1, expected6, Timestamp(12))); + auto expected5 = Document::make_without_repo(getAttrDocType(), DocumentId("id:ns:foo::xx10")); + expected5->setValue("header", StringFieldValue::make("foo")); + expected5->setValue("body", StringFieldValue::make("bar")); + expected5->setValue("aa", IntFieldValue::make(27)); + expected5->setValue("ab", IntFieldValue::make(28)); + expected5->setValue("dd", DoubleFieldValue::make(2.7)); + expected5->setValue("ss", StringFieldValue::make("x27")); + auto expected6 = Document::make_without_repo(getAttrDocType(), DocumentId("id:ns:foo::xx12")); + expected6->setValue("header", StringFieldValue::make("foo")); + expected6->setValue("body", StringFieldValue::make("bar")); + expected6->setValue("aa", IntFieldValue::make(45)); + expected6->setValue("ab", IntFieldValue::make(46)); + expected6->setValue("dd", DoubleFieldValue::make(4.5)); + expected6->setValue("ss", StringFieldValue::make("x45")); + TEST_DO(checkEntry(res3, 0, *expected5, Timestamp(10))); + TEST_DO(checkEntry(res3, 1, *expected6, Timestamp(12))); } TEST_MAIN() { TEST_RUN_ALL(); } diff --git a/searchcore/src/tests/proton/documentdb/maintenancecontroller/maintenancecontroller_test.cpp b/searchcore/src/tests/proton/documentdb/maintenancecontroller/maintenancecontroller_test.cpp index 5afe0a0c5a2..bf960768c89 100644 --- a/searchcore/src/tests/proton/documentdb/maintenancecontroller/maintenancecontroller_test.cpp +++ b/searchcore/src/tests/proton/documentdb/maintenancecontroller/maintenancecontroller_test.cpp @@ -516,8 +516,7 @@ MyDocumentSubDB::handleRemove(RemoveOperationWithDocId &op) assert(op.getLid() == putRes._lid); const document::DocumentType *docType = _repo->getDocumentType(_docTypeName.getName()); - auto doc = std::make_unique<Document>(*docType, docId); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *docType, docId); _docs[op.getLid()] = std::move(doc); needCommit = true; } diff --git a/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp b/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp index 87947788bdf..0479fa61e2b 100644 --- a/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp +++ b/searchcore/src/tests/proton/feedoperation/feedoperation_test.cpp @@ -126,7 +126,7 @@ public: return upd; } auto makeDoc() { - auto doc(std::make_shared<Document>(_docType, docId)); + auto doc(std::make_shared<Document>(*_repo, _docType, docId)); doc->setValue("string", StringFieldValue("stringval")); return doc; } diff --git a/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp b/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp index e9fd4fa9d37..996d9846934 100644 --- a/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp +++ b/searchcore/src/tests/proton/persistenceengine/persistenceengine_test.cpp @@ -61,7 +61,7 @@ createDocType(const vespalib::string &name, int32_t id) Document::SP createDoc(const DocumentType &docType, const DocumentId &docId) { - return std::make_shared<Document>(docType, docId); + return Document::SP(Document::make_without_repo(docType, docId).release()); } diff --git a/searchcore/src/tests/proton/server/documentretriever_test.cpp b/searchcore/src/tests/proton/server/documentretriever_test.cpp index 6cc2ca22531..f99c3ab0f67 100644 --- a/searchcore/src/tests/proton/server/documentretriever_test.cpp +++ b/searchcore/src/tests/proton/server/documentretriever_test.cpp @@ -161,7 +161,7 @@ struct MyDocumentStore : proton::test::DummyDocumentStore { return std::move(_testDoc); } const DocumentType *doc_type = r.getDocumentType(doc_type_name); - auto doc = std::make_unique<Document>(*doc_type, doc_id); + auto doc = std::make_unique<Document>(r, *doc_type, doc_id); ASSERT_TRUE(doc); doc->setValue(static_field, IntFieldValue::make(static_value)); doc->setValue(dyn_field_i, IntFieldValue::make(static_value)); diff --git a/searchcore/src/vespa/searchcore/bmcluster/bm_feed.cpp b/searchcore/src/vespa/searchcore/bmcluster/bm_feed.cpp index 0856bad0035..b257f85acdc 100644 --- a/searchcore/src/vespa/searchcore/bmcluster/bm_feed.cpp +++ b/searchcore/src/vespa/searchcore/bmcluster/bm_feed.cpp @@ -60,8 +60,7 @@ std::unique_ptr<Document> BmFeed::make_document(uint32_t n, uint32_t i) const { auto id = make_document_id(n, i); - auto document = std::make_unique<Document>(*_document_type, id); - document->setRepo(*_repo); + auto document = std::make_unique<Document>(*_repo, *_document_type, id); document->setFieldValue(_field, IntFieldValue::make(i)); return document; } diff --git a/searchcore/src/vespa/searchcore/proton/server/documentretriever.cpp b/searchcore/src/vespa/searchcore/proton/server/documentretriever.cpp index ee2af5b606c..b8240b33b6c 100644 --- a/searchcore/src/vespa/searchcore/proton/server/documentretriever.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/documentretriever.cpp @@ -244,7 +244,7 @@ DocumentRetriever::getPartialDocument(search::DocumentIdT lid, const document::D FieldSet::stripFields(*doc, fieldSet); } } else { - doc = std::make_unique<Document>(getDocumentType(), docId); + doc = std::make_unique<Document>(getDocumentTypeRepo(), getDocumentType(), docId); switch (fieldSet.getType()) { case FieldSet::Type::ALL: populate(lid, *doc); @@ -271,7 +271,6 @@ DocumentRetriever::getPartialDocument(search::DocumentIdT lid, const document::D case FieldSet::Type::DOCID: break; } - doc->setRepo(getDocumentTypeRepo()); } return doc; } diff --git a/searchcore/src/vespa/searchcore/proton/server/documentretrieverbase.cpp b/searchcore/src/vespa/searchcore/proton/server/documentretrieverbase.cpp index 914f3d8bcfd..bb7d80c5ebc 100644 --- a/searchcore/src/vespa/searchcore/proton/server/documentretrieverbase.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/documentretrieverbase.cpp @@ -26,8 +26,7 @@ DocumentRetrieverBase::DocumentRetrieverBase( _hasFields(hasFields) { const document::DocumentType * docType(_repo.getDocumentType(_docTypeName.getName())); - _emptyDoc = std::make_unique<document::Document>(*docType, DocumentId("id:empty:" + _docTypeName.getName() + "::empty")); - _emptyDoc->setRepo(_repo); + _emptyDoc = std::make_unique<document::Document>(_repo, *docType, DocumentId("id:empty:" + _docTypeName.getName() + "::empty")); } DocumentRetrieverBase::~DocumentRetrieverBase() = default; diff --git a/searchcore/src/vespa/searchcore/proton/server/feedhandler.cpp b/searchcore/src/vespa/searchcore/proton/server/feedhandler.cpp index 6bbedcdb18e..e9a14385c6a 100644 --- a/searchcore/src/vespa/searchcore/proton/server/feedhandler.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/feedhandler.cpp @@ -217,8 +217,8 @@ FeedHandler::performInternalUpdate(FeedToken token, UpdateOperation &op) void FeedHandler::createNonExistingDocument(FeedToken token, const UpdateOperation &op) { - auto doc = make_shared<Document>(op.getUpdate()->getType(), op.getUpdate()->getId()); - doc->setRepo(*_activeFeedView->getDocumentTypeRepo()); + auto doc = make_shared<Document>(*_activeFeedView->getDocumentTypeRepo(), + op.getUpdate()->getType(), op.getUpdate()->getId()); op.getUpdate()->applyTo(*doc); PutOperation putOp(op.getBucketId(), op.getTimestamp(), std::move(doc)); putOp.set_prepare_serial_num(op.get_prepare_serial_num()); diff --git a/searchcore/src/vespa/searchcore/proton/server/storeonlyfeedview.cpp b/searchcore/src/vespa/searchcore/proton/server/storeonlyfeedview.cpp index 533b270c20a..c2b4c0507db 100644 --- a/searchcore/src/vespa/searchcore/proton/server/storeonlyfeedview.cpp +++ b/searchcore/src/vespa/searchcore/proton/server/storeonlyfeedview.cpp @@ -586,8 +586,7 @@ StoreOnlyFeedView::internalRemove(FeedToken token, const RemoveOperationWithDocI adjustMetaStore(rmOp, docId.getGlobalId(), docId); if (rmOp.getValidDbdId(_params._subDbId)) { - auto clearDoc = std::make_unique<Document>(*_docType, docId); - clearDoc->setRepo(*_repo); + auto clearDoc = std::make_unique<Document>(*_repo, *_docType, docId); putSummary(serialNum, rmOp.getLid(), std::move(clearDoc), std::make_shared<SummaryPutDoneContext>(std::move(token), get_pending_lid_token(rmOp))); } diff --git a/searchlib/src/apps/tests/memoryindexstress_test.cpp b/searchlib/src/apps/tests/memoryindexstress_test.cpp index fb743ad93ac..fdb132d9a36 100644 --- a/searchlib/src/apps/tests/memoryindexstress_test.cpp +++ b/searchlib/src/apps/tests/memoryindexstress_test.cpp @@ -153,8 +153,7 @@ makeDoc(const DocumentTypeRepo &repo, uint32_t i, idstr << "id:test:test:: " << i; DocumentId id(idstr.str()); const DocumentType *docType = repo.getDocumentType(doc_type_name); - auto doc(std::make_unique<Document>(*docType, id)); - doc->setRepo(repo); + auto doc(std::make_unique<Document>(repo, *docType, id)); if (!titleString.empty()) { setFieldValue(*doc, title, titleString); } diff --git a/searchlib/src/tests/attribute/attribute_test.cpp b/searchlib/src/tests/attribute/attribute_test.cpp index 16b5ef78951..f336742ca4b 100644 --- a/searchlib/src/tests/attribute/attribute_test.cpp +++ b/searchlib/src/tests/attribute/attribute_test.cpp @@ -912,8 +912,8 @@ AttributeTest::testSingle() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("sv-post-int32", cfg); ptr->updateStat(true); - EXPECT_EQ(887756u, ptr->getStatus().getAllocated()); - EXPECT_EQ(656444u, ptr->getStatus().getUsed()); + EXPECT_EQ(347084u, ptr->getStatus().getAllocated()); + EXPECT_EQ(101852u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testSingle<IntegerAttribute, AttributeVector::largeint_t, int32_t>(ptr, values); } @@ -934,8 +934,8 @@ AttributeTest::testSingle() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("sv-post-float", cfg); ptr->updateStat(true); - EXPECT_EQ(887756u, ptr->getStatus().getAllocated()); - EXPECT_EQ(656444u, ptr->getStatus().getUsed()); + EXPECT_EQ(347084u, ptr->getStatus().getAllocated()); + EXPECT_EQ(101852u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testSingle<FloatingPointAttribute, double, float>(ptr, values); } @@ -947,8 +947,8 @@ AttributeTest::testSingle() { AttributePtr ptr = createAttribute("sv-string", Config(BasicType::STRING, CollectionType::SINGLE)); ptr->updateStat(true); - EXPECT_EQ(403552u, ptr->getStatus().getAllocated()); - EXPECT_EQ(328576u, ptr->getStatus().getUsed()); + EXPECT_EQ(133216u, ptr->getStatus().getAllocated()); + EXPECT_EQ(53280u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testSingle<StringAttribute, string, string>(ptr, values); } @@ -957,8 +957,8 @@ AttributeTest::testSingle() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("sv-fs-string", cfg); ptr->updateStat(true); - EXPECT_EQ(902256u, ptr->getStatus().getAllocated()); - EXPECT_EQ(657088u, ptr->getStatus().getUsed()); + EXPECT_EQ(361584u, ptr->getStatus().getAllocated()); + EXPECT_EQ(105216u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testSingle<StringAttribute, string, string>(ptr, values); } @@ -1089,8 +1089,8 @@ AttributeTest::testArray() { AttributePtr ptr = createAttribute("a-int32", Config(BasicType::INT32, CollectionType::ARRAY)); ptr->updateStat(true); - EXPECT_EQ(1474480u, ptr->getStatus().getAllocated()); - EXPECT_EQ(1462192u, ptr->getStatus().getUsed()); + EXPECT_EQ(528304u, ptr->getStatus().getAllocated()); + EXPECT_EQ(512576u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<IntegerAttribute, AttributeVector::largeint_t>(ptr, values); } @@ -1099,8 +1099,8 @@ AttributeTest::testArray() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("flags", cfg); ptr->updateStat(true); - EXPECT_EQ(1474480u, ptr->getStatus().getAllocated()); - EXPECT_EQ(1462192u, ptr->getStatus().getUsed()); + EXPECT_EQ(528304u, ptr->getStatus().getAllocated()); + EXPECT_EQ(512576u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<IntegerAttribute, AttributeVector::largeint_t>(ptr, values); } @@ -1109,8 +1109,8 @@ AttributeTest::testArray() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("a-fs-int32", cfg); ptr->updateStat(true); - EXPECT_EQ(2371884u, ptr->getStatus().getAllocated()); - EXPECT_EQ(2118656u, ptr->getStatus().getUsed()); + EXPECT_EQ(885036u, ptr->getStatus().getAllocated()); + EXPECT_EQ(614448u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<IntegerAttribute, AttributeVector::largeint_t>(ptr, values); } @@ -1128,8 +1128,8 @@ AttributeTest::testArray() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("a-fs-float", cfg); ptr->updateStat(true); - EXPECT_EQ(2371884u, ptr->getStatus().getAllocated()); - EXPECT_EQ(2118656u, ptr->getStatus().getUsed()); + EXPECT_EQ(885036u, ptr->getStatus().getAllocated()); + EXPECT_EQ(614448u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<FloatingPointAttribute, double>(ptr, values); } @@ -1140,8 +1140,8 @@ AttributeTest::testArray() { AttributePtr ptr = createAttribute("a-string", Config(BasicType::STRING, CollectionType::ARRAY)); ptr->updateStat(true); - EXPECT_EQ(1865744u, ptr->getStatus().getAllocated()); - EXPECT_EQ(1790768u, ptr->getStatus().getUsed()); + EXPECT_EQ(649232u, ptr->getStatus().getAllocated()); + EXPECT_EQ(565856u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<StringAttribute, string>(ptr, values); } @@ -1150,8 +1150,8 @@ AttributeTest::testArray() cfg.setFastSearch(true); AttributePtr ptr = createAttribute("afs-string", cfg); ptr->updateStat(true); - EXPECT_EQ(2386384u, ptr->getStatus().getAllocated()); - EXPECT_EQ(2119300u, ptr->getStatus().getUsed()); + EXPECT_EQ(899536u, ptr->getStatus().getAllocated()); + EXPECT_EQ(617812u, ptr->getStatus().getUsed()); addDocs(ptr, numDocs); testArray<StringAttribute, string>(ptr, values); } diff --git a/searchlib/src/tests/attribute/postinglist/postinglist.cpp b/searchlib/src/tests/attribute/postinglist/postinglist.cpp index 7d2a89b6e5b..39e31b23498 100644 --- a/searchlib/src/tests/attribute/postinglist/postinglist.cpp +++ b/searchlib/src/tests/attribute/postinglist/postinglist.cpp @@ -581,21 +581,15 @@ AttributePostingListTest::doCompactEnumStore(Tree &tree, TreeManager &treeMgr, ValueHandle &valueHandle) { - LOG(info, - "doCompactEnumStore start"); + LOG(info,"doCompactEnumStore start"); Tree::Iterator i = tree.begin(treeMgr); - uint32_t numBuffers = valueHandle.getNumBuffers(); std::vector<uint32_t> toHold; + valueHandle.for_each_active_buffer([&toHold](uint32_t buffer_id, const vespalib::datastore::BufferState &) { + toHold.push_back(buffer_id); + }); - for (uint32_t bufferId = 0; bufferId < numBuffers; ++bufferId) { - vespalib::datastore::BufferState &state = valueHandle.getBufferState(bufferId); - if (state.isActive()) { - toHold.push_back(bufferId); - // Freelists already disabled due to variable sized data - } - } valueHandle.switch_primary_buffer(0, 0u); for (; i.valid(); ++i) diff --git a/searchlib/src/tests/docstore/document_store_visitor/document_store_visitor_test.cpp b/searchlib/src/tests/docstore/document_store_visitor/document_store_visitor_test.cpp index efe858c016a..e841e334215 100644 --- a/searchlib/src/tests/docstore/document_store_visitor/document_store_visitor_test.cpp +++ b/searchlib/src/tests/docstore/document_store_visitor/document_store_visitor_test.cpp @@ -60,7 +60,7 @@ makeDoc(const DocumentTypeRepo &repo, uint32_t i, bool before) idstr << "id:test:test:: " << i; DocumentId id(idstr.str()); const DocumentType *docType = repo.getDocumentType(doc_type_name); - Document::UP doc(new Document(*docType, id)); + Document::UP doc(new Document(repo, *docType, id)); ASSERT_TRUE(doc.get()); asciistream mainstr; mainstr << "static text" << i << " body something"; diff --git a/searchlib/src/tests/docstore/logdatastore/logdatastore_test.cpp b/searchlib/src/tests/docstore/logdatastore/logdatastore_test.cpp index 414e06bd464..580fd199806 100644 --- a/searchlib/src/tests/docstore/logdatastore/logdatastore_test.cpp +++ b/searchlib/src/tests/docstore/logdatastore/logdatastore_test.cpp @@ -426,7 +426,7 @@ makeDoc(const DocumentTypeRepo &repo, uint32_t i, bool extra_field, size_t numRe idstr << "id:test:test:: " << i; DocumentId id(idstr.str()); const DocumentType *docType = repo.getDocumentType(doc_type_name); - Document::UP doc(new Document(*docType, id)); + Document::UP doc(new Document(repo, *docType, id)); ASSERT_TRUE(doc.get()); asciistream mainstr; mainstr << "static text" << i << " body something"; diff --git a/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp b/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp index 1b1c1181666..8073fb8d232 100644 --- a/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp +++ b/searchlib/src/tests/memoryindex/memory_index/memory_index_test.cpp @@ -462,8 +462,8 @@ TEST(MemoryIndexTest, require_that_num_docs_and_doc_id_limit_is_returned) TEST(MemoryIndexTest, require_that_we_understand_the_memory_footprint) { - constexpr size_t BASE_ALLOCATED = 1172040u; - constexpr size_t BASE_USED = 984116u; + constexpr size_t BASE_ALLOCATED = 361032u; + constexpr size_t BASE_USED = 151188u; { MySetup setup; Index index(setup); diff --git a/searchlib/src/tests/predicate/document_features_store_test.cpp b/searchlib/src/tests/predicate/document_features_store_test.cpp index c37fe2739ca..4ac4bdc32f0 100644 --- a/searchlib/src/tests/predicate/document_features_store_test.cpp +++ b/searchlib/src/tests/predicate/document_features_store_test.cpp @@ -165,17 +165,17 @@ TEST("require that both features and ranges are removed by 'remove'") { TEST("require that both features and ranges counts towards memory usage") { DocumentFeaturesStore features_store(10); - EXPECT_EQUAL(328152u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50136u, features_store.getMemoryUsage().usedBytes()); PredicateTreeAnnotations annotations; annotations.features.push_back(PredicateHash::hash64("foo=100-199")); features_store.insert(annotations, doc_id); - EXPECT_EQUAL(328160u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50144u, features_store.getMemoryUsage().usedBytes()); annotations.features.clear(); annotations.range_features.push_back({"foo", 100, 199}); features_store.insert(annotations, doc_id + 1); - EXPECT_EQUAL(328256u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50240u, features_store.getMemoryUsage().usedBytes()); } TEST("require that DocumentFeaturesStore can be serialized") { @@ -205,17 +205,17 @@ TEST("require that serialization cleans up wordstore") { PredicateTreeAnnotations annotations; annotations.range_features.push_back({"foo", 100, 199}); features_store.insert(annotations, doc_id); - EXPECT_EQUAL(328248u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50232u, features_store.getMemoryUsage().usedBytes()); annotations.range_features.push_back({"bar", 100, 199}); features_store.insert(annotations, doc_id + 1); - EXPECT_EQUAL(328636u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50620u, features_store.getMemoryUsage().usedBytes()); features_store.remove(doc_id + 1); - EXPECT_EQUAL(328588u, features_store.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50572u, features_store.getMemoryUsage().usedBytes()); vespalib::DataBuffer buffer; features_store.serialize(buffer); DocumentFeaturesStore features_store2(buffer); - EXPECT_EQUAL(328248u, features_store2.getMemoryUsage().usedBytes()); + EXPECT_EQUAL(50232u, features_store2.getMemoryUsage().usedBytes()); } diff --git a/searchlib/src/vespa/searchlib/attribute/postingstore.cpp b/searchlib/src/vespa/searchlib/attribute/postingstore.cpp index 2aa05e7fa9f..94720212faf 100644 --- a/searchlib/src/vespa/searchlib/attribute/postingstore.cpp +++ b/searchlib/src/vespa/searchlib/attribute/postingstore.cpp @@ -727,13 +727,12 @@ template <typename DataT> void PostingStore<DataT>::compact_worst_buffers(CompactionSpec compaction_spec, const CompactionStrategy& compaction_strategy) { - auto compacting_buffers = this->start_compact_worst_buffers(compaction_spec, compaction_strategy); bool compact_btree_roots = false; auto filter = compacting_buffers->make_entry_ref_filter(); // Start with looking at buffers being compacted for (uint32_t buffer_id : compacting_buffers->get_buffer_ids()) { - if (isBTree(_store.getBufferState(buffer_id).getTypeId())) { + if (isBTree(_store.getBufferMeta(buffer_id).getTypeId())) { compact_btree_roots = true; } } diff --git a/searchlib/src/vespa/searchlib/test/doc_builder.cpp b/searchlib/src/vespa/searchlib/test/doc_builder.cpp index 2097cd53b2c..3950a28bea7 100644 --- a/searchlib/src/vespa/searchlib/test/doc_builder.cpp +++ b/searchlib/src/vespa/searchlib/test/doc_builder.cpp @@ -59,8 +59,7 @@ DocBuilder::~DocBuilder() = default; std::unique_ptr<Document> DocBuilder::make_document(vespalib::string document_id) { - auto doc = std::make_unique<Document>(get_document_type(), DocumentId(document_id)); - doc->setRepo(get_repo()); + auto doc = std::make_unique<Document>(get_repo(), get_document_type(), DocumentId(document_id)); return doc; } diff --git a/searchsummary/src/tests/docsummary/document_id_dfw/document_id_dfw_test.cpp b/searchsummary/src/tests/docsummary/document_id_dfw/document_id_dfw_test.cpp index 7e54f35ff38..8dfdd1877f1 100644 --- a/searchsummary/src/tests/docsummary/document_id_dfw/document_id_dfw_test.cpp +++ b/searchsummary/src/tests/docsummary/document_id_dfw/document_id_dfw_test.cpp @@ -95,8 +95,7 @@ DocumentIdDFWTest::~DocumentIdDFWTest() = default; std::unique_ptr<IDocsumStoreDocument> DocumentIdDFWTest::make_docsum_store_document(const vespalib::string& id) { - auto doc = std::make_unique<Document>(*_document_type, DocumentId(id)); - doc->setRepo(*_repo); + auto doc = std::make_unique<Document>(*_repo, *_document_type, DocumentId(id)); return std::make_unique<DocsumStoreDocument>(std::move(doc)); } diff --git a/searchsummary/src/tests/docsummary/matched_elements_filter/matched_elements_filter_test.cpp b/searchsummary/src/tests/docsummary/matched_elements_filter/matched_elements_filter_test.cpp index 7eb634f5609..7b83dbe2c4e 100644 --- a/searchsummary/src/tests/docsummary/matched_elements_filter/matched_elements_filter_test.cpp +++ b/searchsummary/src/tests/docsummary/matched_elements_filter/matched_elements_filter_test.cpp @@ -102,7 +102,7 @@ public: } ~DocsumStore(); std::unique_ptr<IDocsumStoreDocument> getMappedDocsum() { - auto doc = std::make_unique<Document>(_doc_type, DocumentId("id:test:test::0")); + auto doc = Document::make_without_repo(_doc_type, DocumentId("id:test:test::0")); { ArrayFieldValue array_value(_array_type); if (!_empty_values) { diff --git a/searchsummary/src/tests/docsummary/slime_summary/slime_summary_test.cpp b/searchsummary/src/tests/docsummary/slime_summary/slime_summary_test.cpp index 93f87d9c5be..7077f707247 100644 --- a/searchsummary/src/tests/docsummary/slime_summary/slime_summary_test.cpp +++ b/searchsummary/src/tests/docsummary/slime_summary/slime_summary_test.cpp @@ -68,7 +68,7 @@ struct SlimeSummaryTest : testing::Test, IDocsumStore, GetDocsumsStateCallback { if (empty_get_mapped_docsum) { return std::make_unique<DocsumStoreDocument>(std::unique_ptr<Document>()); } - auto doc = std::make_unique<Document>(doc_type, DocumentId("id:test:test::0")); + auto doc = Document::make_without_repo(doc_type, DocumentId("id:test:test::0")); doc->setValue("int_field", IntFieldValue(4)); doc->setValue("short_field", ShortFieldValue(2)); doc->setValue("byte_field", ByteFieldValue(1)); diff --git a/storage/src/tests/bucketdb/bucketmanagertest.cpp b/storage/src/tests/bucketdb/bucketmanagertest.cpp index dc33bfd04e2..ea3a782d432 100644 --- a/storage/src/tests/bucketdb/bucketmanagertest.cpp +++ b/storage/src/tests/bucketdb/bucketmanagertest.cpp @@ -171,7 +171,7 @@ void BucketManagerTest::setupTestEnvironment(bool fakePersistenceLayer, } // Generate a doc to use for testing.. const DocumentType &type(*_node->getTypeRepo()->getDocumentType("text/html")); - _document = std::make_shared<document::Document>(type, document::DocumentId("id:ns:text/html::ntnu")); + _document = std::make_shared<document::Document>(*_node->getTypeRepo(), type, document::DocumentId("id:ns:text/html::ntnu")); } void BucketManagerTest::addBucketsToDB(uint32_t count) diff --git a/storage/src/tests/distributor/bucketdatabasetest.cpp b/storage/src/tests/distributor/bucketdatabasetest.cpp index 661fd7fee72..fcc64e0cccf 100644 --- a/storage/src/tests/distributor/bucketdatabasetest.cpp +++ b/storage/src/tests/distributor/bucketdatabasetest.cpp @@ -87,7 +87,7 @@ struct ListAllProcessor : public BucketDatabase::EntryProcessor { std::string dump_db(const BucketDatabase& db) { ListAllProcessor proc; - db.forEach(proc, document::BucketId()); + db.for_each_upper_bound(proc, document::BucketId()); return proc.ost.str(); } @@ -122,41 +122,70 @@ TEST_P(BucketDatabaseTest, iterating) { { ListAllProcessor proc; - db().forEach(proc, document::BucketId()); - - EXPECT_EQ( - std::string( - "BucketId(0x4000000000000010) : " - "node(idx=1,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n" - "BucketId(0x400000000000002a) : " - "node(idx=3,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n" - "BucketId(0x400000000000000b) : " - "node(idx=2,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n"), - proc.ost.str()); + db().for_each_upper_bound(proc, document::BucketId()); + + EXPECT_EQ("BucketId(0x4000000000000010) : " + "node(idx=1,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n" + "BucketId(0x400000000000002a) : " + "node(idx=3,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n" + "BucketId(0x400000000000000b) : " + "node(idx=2,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n", + proc.ost.str()); } { ListAllProcessor proc; - db().forEach(proc, document::BucketId(16, 0x2a)); + db().for_each_lower_bound(proc, document::BucketId()); // lbound (in practice) equal to ubound when starting at zero + + EXPECT_EQ("BucketId(0x4000000000000010) : " + "node(idx=1,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n" + "BucketId(0x400000000000002a) : " + "node(idx=3,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n" + "BucketId(0x400000000000000b) : " + "node(idx=2,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n", + proc.ost.str()); + } + + { + ListAllProcessor proc; + db().for_each_upper_bound(proc, document::BucketId(16, 0x2a)); + + EXPECT_EQ("BucketId(0x400000000000000b) : " + "node(idx=2,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n", + proc.ost.str()); + } + + { + ListAllProcessor proc; + db().for_each_lower_bound(proc, document::BucketId(16, 0x2a)); + // Includes 0x2a + EXPECT_EQ("BucketId(0x400000000000002a) : " + "node(idx=3,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n" + "BucketId(0x400000000000000b) : " + "node(idx=2,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n", + proc.ost.str()); + } - EXPECT_EQ( - std::string( - "BucketId(0x400000000000000b) : " - "node(idx=2,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n"), - proc.ost.str()); + { + StoppingProcessor proc; + db().for_each_upper_bound(proc, document::BucketId()); + + EXPECT_EQ("BucketId(0x4000000000000010) : " + "node(idx=1,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n" + "BucketId(0x400000000000002a) : " + "node(idx=3,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n", + proc.ost.str()); } { StoppingProcessor proc; - db().forEach(proc, document::BucketId()); - - EXPECT_EQ( - std::string( - "BucketId(0x4000000000000010) : " - "node(idx=1,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n" - "BucketId(0x400000000000002a) : " - "node(idx=3,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n"), - proc.ost.str()); + db().for_each_lower_bound(proc, document::BucketId()); + + EXPECT_EQ("BucketId(0x4000000000000010) : " + "node(idx=1,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n" + "BucketId(0x400000000000002a) : " + "node(idx=3,crc=0x0,docs=0/0,bytes=1/1,trusted=false,active=false,ready=false)\n", + proc.ost.str()); } } @@ -761,7 +790,7 @@ TEST_P(BucketDatabaseTest, DISABLED_benchmark_const_iteration) { auto elapsed = vespalib::BenchmarkTimer::benchmark([&] { DummyProcessor proc; - db().forEach(proc, document::BucketId()); + db().for_each_upper_bound(proc, document::BucketId()); }, 5); fprintf(stderr, "Full DB iteration of %s takes %g seconds\n", db().toString(false).c_str(), elapsed); diff --git a/storage/src/tests/distributor/getoperationtest.cpp b/storage/src/tests/distributor/getoperationtest.cpp index 8d188f6c005..36a1495579f 100644 --- a/storage/src/tests/distributor/getoperationtest.cpp +++ b/storage/src/tests/distributor/getoperationtest.cpp @@ -85,7 +85,7 @@ struct GetOperationTest : Test, DistributorStripeTestUtil { if (!authorVal.empty()) { const document::DocumentType* type(_repo->getDocumentType("text/html")); - doc = std::make_unique<document::Document>(*type, docId); + doc = std::make_unique<document::Document>(*_repo, *type, docId); doc->setValue(doc->getField("author"), document::StringFieldValue(authorVal)); diff --git a/storage/src/tests/distributor/putoperationtest.cpp b/storage/src/tests/distributor/putoperationtest.cpp index 735666e5c89..2a3f06b1e8c 100644 --- a/storage/src/tests/distributor/putoperationtest.cpp +++ b/storage/src/tests/distributor/putoperationtest.cpp @@ -83,8 +83,12 @@ public: return *_testDocMan.getTypeRepo().getDocumentType("testdoctype1"); } + const document::DocumentTypeRepo& type_repo() const { + return _testDocMan.getTypeRepo(); + } + Document::SP createDummyDocument(const char* ns, const char* id) const { - return std::make_shared<Document>(doc_type(), DocumentId(vespalib::make_string("id:%s:testdoctype1::%s", ns, id))); + return std::make_shared<Document>(type_repo(), doc_type(), DocumentId(vespalib::make_string("id:%s:testdoctype1::%s", ns, id))); } static std::shared_ptr<api::PutCommand> createPut(Document::SP doc) { @@ -98,7 +102,7 @@ PutOperationTest::~PutOperationTest() = default; document::BucketId PutOperationTest::createAndSendSampleDocument(vespalib::duration timeout) { - auto doc = std::make_shared<Document>(doc_type(), DocumentId("id:test:testdoctype1::")); + auto doc = std::make_shared<Document>(type_repo(), doc_type(), DocumentId("id:test:testdoctype1::")); document::BucketId id = operation_context().make_split_bit_constrained_bucket_id(doc->getId()); addIdealNodes(id); @@ -453,7 +457,7 @@ TEST_F(PutOperationTest, no_storage_nodes) { TEST_F(PutOperationTest, update_correct_bucket_on_remapped_put) { setup_stripe(2, 2, "storage:2 distributor:1"); - auto doc = std::make_shared<Document>(doc_type(), DocumentId("id:test:testdoctype1:n=13:uri")); + auto doc = std::make_shared<Document>(type_repo(), doc_type(), DocumentId("id:test:testdoctype1:n=13:uri")); addNodesToBucketDB(document::BucketId(16,13), "0=0,1=0"); sendPut(createPut(doc)); diff --git a/storage/src/tests/distributor/top_level_bucket_db_updater_test.cpp b/storage/src/tests/distributor/top_level_bucket_db_updater_test.cpp index 7b4f688b253..d5d33a178fe 100644 --- a/storage/src/tests/distributor/top_level_bucket_db_updater_test.cpp +++ b/storage/src/tests/distributor/top_level_bucket_db_updater_test.cpp @@ -1697,7 +1697,7 @@ TopLevelBucketDBUpdaterTest::merge_bucket_lists( BucketDumper dumper_tmp(true); for (auto* s : distributor_stripes()) { auto& db = s->getBucketSpaceRepo().get(document::FixedBucketSpaces::default_space()).getBucketDatabase(); - db.forEach(dumper_tmp); + db.for_each_upper_bound(dumper_tmp); } { @@ -1717,7 +1717,7 @@ TopLevelBucketDBUpdaterTest::merge_bucket_lists( BucketDumper dumper(include_bucket_info); for (auto* s : distributor_stripes()) { auto& db = s->getBucketSpaceRepo().get(document::FixedBucketSpaces::default_space()).getBucketDatabase(); - db.forEach(dumper); + db.for_each_upper_bound(dumper); db.clear(); } return dumper.ost.str(); diff --git a/storage/src/tests/distributor/twophaseupdateoperationtest.cpp b/storage/src/tests/distributor/twophaseupdateoperationtest.cpp index 579fd156962..da32225cde3 100644 --- a/storage/src/tests/distributor/twophaseupdateoperationtest.cpp +++ b/storage/src/tests/distributor/twophaseupdateoperationtest.cpp @@ -237,7 +237,7 @@ TwoPhaseUpdateOperationTest::replyToGet( std::shared_ptr<api::StorageReply> reply; if (haveDocument) { - auto doc(std::make_shared<Document>(*_doc_type, DocumentId("id:ns:" + _doc_type->getName() + "::1"))); + auto doc(std::make_shared<Document>(*_repo, *_doc_type, DocumentId("id:ns:" + _doc_type->getName() + "::1"))); doc->setValue("headerval", IntFieldValue(oldTimestamp)); reply = std::make_shared<api::GetReply>(get, doc, oldTimestamp); diff --git a/storage/src/tests/persistence/filestorage/filestormanagertest.cpp b/storage/src/tests/persistence/filestorage/filestormanagertest.cpp index 7f3fe06fc29..4227f3dbe13 100644 --- a/storage/src/tests/persistence/filestorage/filestormanagertest.cpp +++ b/storage/src/tests/persistence/filestorage/filestormanagertest.cpp @@ -485,7 +485,7 @@ TEST_F(FileStorManagerTest, flush) { // Creating a document to test with document::DocumentId docId("id:ns:testdoctype1::crawler:http://www.ntnu.no/"); - auto doc = std::make_shared<Document>(*_testdoctype1, docId); + auto doc = std::make_shared<Document>(*_node->getTypeRepo(), *_testdoctype1, docId); document::BucketId bid(4000); static const uint32_t msgCount = 10; @@ -1032,7 +1032,7 @@ FileStorTestBase::putDoc(DummyStorageLink& top, document::BucketId bucket(16, factory.getBucketId(docId).getRawId()); //std::cerr << "doc bucket is " << bucket << " vs source " << source << "\n"; _node->getPersistenceProvider().createBucket(makeSpiBucket(target)); - Document::SP doc(new Document(*_testdoctype1, docId)); + auto doc = std::make_shared<Document>(*_node->getTypeRepo(), *_testdoctype1, docId); auto cmd = std::make_shared<api::PutCommand>(makeDocumentBucket(target), doc, docNum+1); cmd->setAddress(_Storage3); cmd->setPriority(120); @@ -1073,7 +1073,7 @@ TEST_F(FileStorManagerTest, split_empty_target_with_remapped_ops) { document::DocumentId docId( vespalib::make_string("id:ns:testdoctype1:n=%d:1234", 0x100001)); - auto doc = std::make_shared<Document>(*_testdoctype1, docId); + auto doc = std::make_shared<Document>(*_node->getTypeRepo(), *_testdoctype1, docId); auto putCmd = std::make_shared<api::PutCommand>(makeDocumentBucket(source), doc, 1001); putCmd->setAddress(_Storage3); putCmd->setPriority(120); @@ -1399,7 +1399,7 @@ TEST_F(FileStorManagerTest, delete_bucket) { auto& top = c.top; // Creating a document to test with document::DocumentId docId("id:crawler:testdoctype1:n=4000:http://www.ntnu.no/"); - auto doc = std::make_shared<Document>(*_testdoctype1, docId); + auto doc = std::make_shared<Document>(*_node->getTypeRepo(), *_testdoctype1, docId); document::BucketId bid(16, 4000); createBucket(bid); @@ -1440,7 +1440,7 @@ TEST_F(FileStorManagerTest, delete_bucket_rejects_outdated_bucket_info) { auto& top = c.top; // Creating a document to test with document::DocumentId docId("id:crawler:testdoctype1:n=4000:http://www.ntnu.no/"); - Document::SP doc(new Document(*_testdoctype1, docId)); + auto doc = std::make_shared<Document>(*_node->getTypeRepo(), *_testdoctype1, docId); document::BucketId bid(16, 4000); createBucket(bid); @@ -1487,7 +1487,7 @@ TEST_F(FileStorManagerTest, delete_bucket_with_invalid_bucket_info){ auto& top = c.top; // Creating a document to test with document::DocumentId docId("id:crawler:testdoctype1:n=4000:http://www.ntnu.no/"); - auto doc = std::make_shared<Document>(*_testdoctype1, docId); + auto doc = std::make_shared<Document>(*_node->getTypeRepo(), *_testdoctype1, docId); document::BucketId bid(16, 4000); createBucket(bid); diff --git a/storage/src/tests/storageserver/documentapiconvertertest.cpp b/storage/src/tests/storageserver/documentapiconvertertest.cpp index c375443b265..42944c81f13 100644 --- a/storage/src/tests/storageserver/documentapiconvertertest.cpp +++ b/storage/src/tests/storageserver/documentapiconvertertest.cpp @@ -106,7 +106,7 @@ struct DocumentApiConverterTest : Test { }; TEST_F(DocumentApiConverterTest, put) { - auto doc = std::make_shared<Document>(_html_type, defaultDocId); + auto doc = std::make_shared<Document>(*_repo, _html_type, defaultDocId); documentapi::PutDocumentMessage putmsg(doc); putmsg.setTimestamp(1234); @@ -126,7 +126,7 @@ TEST_F(DocumentApiConverterTest, put) { } TEST_F(DocumentApiConverterTest, forwarded_put) { - auto doc = std::make_shared<Document>(_html_type, DocumentId("id:ns:" + _html_type.getName() + "::test")); + auto doc = std::make_shared<Document>(*_repo, _html_type, DocumentId("id:ns:" + _html_type.getName() + "::test")); auto putmsg = std::make_unique<documentapi::PutDocumentMessage>(doc); auto* putmsg_raw = putmsg.get(); diff --git a/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp b/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp index bfc22b9f1ea..26c5b8df5a5 100644 --- a/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp +++ b/storage/src/tests/storageserver/rpc/storage_api_rpc_service_test.cpp @@ -161,7 +161,7 @@ public: std::shared_ptr<api::PutCommand> create_dummy_put_command() const { auto doc_type = _doc_type_repo->getDocumentType("testdoctype1"); - auto doc = std::make_shared<document::Document>(*doc_type, document::DocumentId("id:foo:testdoctype1::bar")); + auto doc = std::make_shared<document::Document>(*_doc_type_repo, *doc_type, document::DocumentId("id:foo:testdoctype1::bar")); doc->setFieldValue(doc->getField("hstringval"), std::make_unique<document::StringFieldValue>("hello world")); return std::make_shared<api::PutCommand>(makeDocumentBucket(document::BucketId(0)), std::move(doc), 100); } diff --git a/storage/src/vespa/storage/bucketdb/btree_bucket_database.cpp b/storage/src/vespa/storage/bucketdb/btree_bucket_database.cpp index 23421e724a2..baec5494b36 100644 --- a/storage/src/vespa/storage/bucketdb/btree_bucket_database.cpp +++ b/storage/src/vespa/storage/bucketdb/btree_bucket_database.cpp @@ -151,9 +151,16 @@ BTreeBucketDatabase::process_update(const document::BucketId& bucket, EntryUpdat } // TODO need snapshot read with guarding -// FIXME semantics of for-each in judy and bit tree DBs differ, former expects lbound, latter ubound..! -// FIXME but bit-tree code says "lowerBound" in impl and "after" in declaration??? -void BTreeBucketDatabase::forEach(EntryProcessor& proc, const BucketId& after) const { +void BTreeBucketDatabase::for_each_lower_bound(EntryProcessor& proc, const BucketId& at_or_after) const { + for (auto iter = _impl->lower_bound(at_or_after.toKey()); iter.valid(); ++iter) { + if (!proc.process(_impl->const_value_ref_from_valid_iterator(iter))) { + break; + } + } +} + +// TODO need snapshot read with guarding +void BTreeBucketDatabase::for_each_upper_bound(EntryProcessor& proc, const BucketId& after) const { for (auto iter = _impl->upper_bound(after.toKey()); iter.valid(); ++iter) { if (!proc.process(_impl->const_value_ref_from_valid_iterator(iter))) { break; diff --git a/storage/src/vespa/storage/bucketdb/btree_bucket_database.h b/storage/src/vespa/storage/bucketdb/btree_bucket_database.h index c20dad13618..3cf77b5444b 100644 --- a/storage/src/vespa/storage/bucketdb/btree_bucket_database.h +++ b/storage/src/vespa/storage/bucketdb/btree_bucket_database.h @@ -44,7 +44,8 @@ public: std::vector<Entry>& entries) const override; void update(const Entry& newEntry) override; void process_update(const document::BucketId& bucket, EntryUpdateProcessor &processor, bool create_if_nonexisting) override; - void forEach(EntryProcessor&, const document::BucketId& after) const override; + void for_each_lower_bound(EntryProcessor&, const document::BucketId& at_or_after) const override; + void for_each_upper_bound(EntryProcessor&, const document::BucketId& after) const override; Entry upperBound(const document::BucketId& value) const override; uint64_t size() const override; void clear() override; diff --git a/storage/src/vespa/storage/bucketdb/bucketdatabase.h b/storage/src/vespa/storage/bucketdb/bucketdatabase.h index d3d9c34c7fc..4e0b727036a 100644 --- a/storage/src/vespa/storage/bucketdb/bucketdatabase.h +++ b/storage/src/vespa/storage/bucketdb/bucketdatabase.h @@ -99,9 +99,15 @@ public: virtual void process_update(const document::BucketId& bucket, EntryUpdateProcessor &processor, bool create_if_nonexisting) = 0; - virtual void forEach( - EntryProcessor&, - const document::BucketId& after = document::BucketId()) const = 0; + virtual void for_each_lower_bound(EntryProcessor&, const document::BucketId& at_or_after) const = 0; + void for_each_lower_bound(EntryProcessor& proc) const { + for_each_lower_bound(proc, document::BucketId()); + } + + virtual void for_each_upper_bound(EntryProcessor&, const document::BucketId& after) const = 0; + void for_each_upper_bound(EntryProcessor& proc) const { + for_each_upper_bound(proc, document::BucketId()); + } using TrailingInserter = bucketdb::TrailingInserter<Entry>; using Merger = bucketdb::Merger<Entry>; diff --git a/storage/src/vespa/storage/distributor/idealstatemanager.cpp b/storage/src/vespa/storage/distributor/idealstatemanager.cpp index cf255b5ec18..2c33bc490fe 100644 --- a/storage/src/vespa/storage/distributor/idealstatemanager.cpp +++ b/storage/src/vespa/storage/distributor/idealstatemanager.cpp @@ -265,7 +265,7 @@ IdealStateManager::getBucketStatus( void IdealStateManager::dump_bucket_space_db_status(document::BucketSpace bucket_space, std::ostream& out) const { StatusBucketVisitor proc(*this, bucket_space, out); auto& distributorBucketSpace = _op_ctx.bucket_space_repo().get(bucket_space); - distributorBucketSpace.getBucketDatabase().forEach(proc); + distributorBucketSpace.getBucketDatabase().for_each_upper_bound(proc); } void IdealStateManager::getBucketStatus(std::ostream& out) const { diff --git a/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp b/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp index bdf4fa2ba72..515b72520ec 100644 --- a/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp +++ b/storage/src/vespa/storage/distributor/operations/external/twophaseupdateoperation.cpp @@ -672,8 +672,7 @@ std::shared_ptr<document::Document> TwoPhaseUpdateOperation::createBlankDocument() const { const document::DocumentUpdate& up(*_updateCmd->getUpdate()); - auto doc = std::make_shared<document::Document>(up.getType(), up.getId()); - doc->setRepo(*up.getRepoPtr()); + auto doc = std::make_shared<document::Document>(*up.getRepoPtr(), up.getType(), up.getId()); return doc; } diff --git a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp index 9e9196dbee7..ca47ab7478c 100644 --- a/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp +++ b/storage/src/vespa/storage/distributor/operations/external/visitoroperation.cpp @@ -388,23 +388,19 @@ VisitorOperation::pickBucketsToVisit(const std::vector<BucketDatabase::Entry>& b std::vector<document::BucketId> bucketVisitOrder; - for (uint32_t i = 0; i < buckets.size(); ++i) { - bucketVisitOrder.push_back(buckets[i].getBucketId()); + for (const auto& bucket : buckets) { + bucketVisitOrder.push_back(bucket.getBucketId()); } VisitorOrder bucketLessThan; std::sort(bucketVisitOrder.begin(), bucketVisitOrder.end(), bucketLessThan); - std::vector<document::BucketId>::const_iterator iter(bucketVisitOrder.begin()); - std::vector<document::BucketId>::const_iterator end(bucketVisitOrder.end()); + auto iter = bucketVisitOrder.begin(); + auto end = bucketVisitOrder.end(); for (; iter != end; ++iter) { - if (bucketLessThan(*iter, _lastBucket) || - *iter == _lastBucket) - { - LOG(spam, - "Skipping bucket %s because it is lower than or equal to progress bucket %s", - iter->toString().c_str(), - _lastBucket.toString().c_str()); + if (bucketLessThan(*iter, _lastBucket) || *iter == _lastBucket) { + LOG(spam, "Skipping bucket %s because it is lower than or equal to progress bucket %s", + iter->toString().c_str(), _lastBucket.toString().c_str()); continue; } LOG(spam, "Iterating: Found in db: %s", iter->toString().c_str()); @@ -460,11 +456,11 @@ getBucketIdAndLast(BucketDatabase& database, { if (!super.contains(last)) { NextEntryFinder proc(super); - database.forEach(proc, super); + database.for_each_upper_bound(proc, super); return proc._next; } else { NextEntryFinder proc(last); - database.forEach(proc, last); + database.for_each_upper_bound(proc, last); return proc._next; } } diff --git a/streamingvisitors/src/tests/document/document.cpp b/streamingvisitors/src/tests/document/document.cpp index 1e97d232a64..acebd9ed4a4 100644 --- a/streamingvisitors/src/tests/document/document.cpp +++ b/streamingvisitors/src/tests/document/document.cpp @@ -29,7 +29,7 @@ DocumentTest::testStorageDocument() dt.addField(fa); dt.addField(fb); - document::Document::UP doc(new document::Document(dt, DocumentId())); + auto doc = document::Document::make_without_repo(dt, DocumentId()); doc->setValue(fa, StringFieldValue("foo")); doc->setValue(fb, StringFieldValue("bar")); diff --git a/streamingvisitors/src/tests/hitcollector/hitcollector_test.cpp b/streamingvisitors/src/tests/hitcollector/hitcollector_test.cpp index 9715b44b27b..6950c90f097 100644 --- a/streamingvisitors/src/tests/hitcollector/hitcollector_test.cpp +++ b/streamingvisitors/src/tests/hitcollector/hitcollector_test.cpp @@ -77,8 +77,8 @@ HitCollectorTest::assertHit(SearchResult::RankType expRank, uint32_t expDocId, u void HitCollectorTest::addHit(HitCollector &hc, uint32_t docId, double score, const char *sortData, size_t sortDataSize) { - document::Document::UP doc(new document::Document(_docType, DocumentId("id:ns:testdoc::"))); - StorageDocument::UP sdoc(new StorageDocument(std::move(doc), SharedFieldPathMap(), 0)); + auto doc = document::Document::make_without_repo(_docType, DocumentId("id:ns:testdoc::")); + auto sdoc = std::make_unique<StorageDocument>(std::move(doc), SharedFieldPathMap(), 0); ASSERT_TRUE(sdoc->valid()); MatchData md(MatchData::params()); hc.addHit(sdoc.get(), docId, md, score, sortData, sortDataSize); diff --git a/streamingvisitors/src/tests/matching_elements_filler/matching_elements_filler_test.cpp b/streamingvisitors/src/tests/matching_elements_filler/matching_elements_filler_test.cpp index 59e84b7d08c..458031b5f01 100644 --- a/streamingvisitors/src/tests/matching_elements_filler/matching_elements_filler_test.cpp +++ b/streamingvisitors/src/tests/matching_elements_filler/matching_elements_filler_test.cpp @@ -211,7 +211,7 @@ MyDocType::make_field_path(vespalib::string path) const std::unique_ptr<document::Document> MyDocType::make_test_doc() const { - auto doc = std::make_unique<document::Document>(_document_type, DocumentId("id::test::1")); + auto doc = document::Document::make_without_repo(_document_type, DocumentId("id::test::1")); doc->setValue("elem_array", *make_elem_array({{"foo", 10},{"bar", 20},{"baz", 30},{"foo", 40}, {"zap", 20}, {"zap", 20}})); // the elements in maps are ordered on the key doc->setValue("elem_map", *make_elem_map({{"@foo", {"foo", 10}}, {"@bar", {"bar", 20}},{"@baz", {"baz", 30}},{"@foo@", {"foo", 40}},{"@zap", {"zap", 20}}, {"@zap@", {"zap", 20}}})); diff --git a/vespalib/src/tests/btree/btree_test.cpp b/vespalib/src/tests/btree/btree_test.cpp index ef64549e16a..b8da9ea6042 100644 --- a/vespalib/src/tests/btree/btree_test.cpp +++ b/vespalib/src/tests/btree/btree_test.cpp @@ -1064,7 +1064,8 @@ adjustAllocatedBytes(size_t nodeCount, size_t nodeSize) TEST_F(BTreeTest, require_that_memory_usage_is_calculated) { - constexpr size_t BASE = 163912; + constexpr size_t BASE_ALLOCATED = 28744u; + constexpr size_t BASE_USED = 24984; typedef BTreeNodeAllocator<int32_t, int8_t, btree::NoAggregated, MyTraits::INTERNAL_SLOTS, MyTraits::LEAF_SLOTS> NodeAllocator; @@ -1083,8 +1084,8 @@ TEST_F(BTreeTest, require_that_memory_usage_is_calculated) const uint32_t initialLeafNodes = 128u; mu.incAllocatedBytes(adjustAllocatedBytes(initialInternalNodes, sizeof(INode))); mu.incAllocatedBytes(adjustAllocatedBytes(initialLeafNodes, sizeof(LNode))); - mu.incAllocatedBytes(BASE); - mu.incUsedBytes(BASE); + mu.incAllocatedBytes(BASE_ALLOCATED); + mu.incUsedBytes(BASE_USED); mu.incUsedBytes(sizeof(INode)); mu.incDeadBytes(sizeof(INode)); EXPECT_TRUE(assertMemoryUsage(mu, tm.getMemoryUsage())); @@ -1115,8 +1116,8 @@ TEST_F(BTreeTest, require_that_memory_usage_is_calculated) mu = vespalib::MemoryUsage(); mu.incAllocatedBytes(adjustAllocatedBytes(initialInternalNodes, sizeof(INode))); mu.incAllocatedBytes(adjustAllocatedBytes(initialLeafNodes, sizeof(LNode))); - mu.incAllocatedBytes(BASE); - mu.incUsedBytes(BASE); + mu.incAllocatedBytes(BASE_ALLOCATED); + mu.incUsedBytes(BASE_USED); mu.incUsedBytes(sizeof(INode) * 2); mu.incDeadBytes(sizeof(INode) * 2); mu.incUsedBytes(sizeof(LNode)); diff --git a/vespalib/src/tests/datastore/array_store/array_store_test.cpp b/vespalib/src/tests/datastore/array_store/array_store_test.cpp index 97e1ddb985d..c32554232ef 100644 --- a/vespalib/src/tests/datastore/array_store/array_store_test.cpp +++ b/vespalib/src/tests/datastore/array_store/array_store_test.cpp @@ -210,16 +210,16 @@ INSTANTIATE_TEST_SUITE_P(NumberStoreFreeListsDisabledMultiTest, TEST_P(NumberStoreTest, control_static_sizes) { #ifdef _LIBCPP_VERSION - EXPECT_EQ(472u, sizeof(store)); - EXPECT_EQ(296u, sizeof(NumberStoreTest::ArrayStoreType::DataStoreType)); + EXPECT_EQ(464u, sizeof(store)); + EXPECT_EQ(280u, sizeof(NumberStoreTest::ArrayStoreType::DataStoreType)); #else - EXPECT_EQ(504u, sizeof(store)); - EXPECT_EQ(328u, sizeof(NumberStoreTest::ArrayStoreType::DataStoreType)); + EXPECT_EQ(496u, sizeof(store)); + EXPECT_EQ(320u, sizeof(NumberStoreTest::ArrayStoreType::DataStoreType)); #endif EXPECT_EQ(112u, sizeof(NumberStoreTest::ArrayStoreType::SmallBufferType)); MemoryUsage usage = store.getMemoryUsage(); - EXPECT_EQ(1312160u, usage.allocatedBytes()); - EXPECT_EQ(1311232u, usage.usedBytes()); + EXPECT_EQ(202144u, usage.allocatedBytes()); + EXPECT_EQ(197776u, usage.usedBytes()); } TEST_P(NumberStoreTest, add_and_get_small_arrays_of_trivial_type) diff --git a/vespalib/src/tests/datastore/datastore/datastore_test.cpp b/vespalib/src/tests/datastore/datastore/datastore_test.cpp index 794be39ae9b..7121bf5ce11 100644 --- a/vespalib/src/tests/datastore/datastore/datastore_test.cpp +++ b/vespalib/src/tests/datastore/datastore/datastore_test.cpp @@ -474,7 +474,8 @@ TEST(DataStoreTest, require_that_memory_stats_are_calculated) TEST(DataStoreTest, require_that_memory_usage_is_calculated) { - constexpr size_t BASE = 676; + constexpr size_t BASE_ALLOCATED = 4228; + constexpr size_t BASE_USED = 308; MyStore s; MyRef r = s.addEntry(10); s.addEntry(20); @@ -483,8 +484,8 @@ TEST(DataStoreTest, require_that_memory_usage_is_calculated) s.holdBuffer(r.bufferId()); s.assign_generation(100); vespalib::MemoryUsage m = s.getMemoryUsage(); - EXPECT_EQ(MyRef::offsetSize() * sizeof(int) + BASE, m.allocatedBytes()); - EXPECT_EQ(5 * sizeof(int) + BASE, m.usedBytes()); + EXPECT_EQ(MyRef::offsetSize() * sizeof(int) + BASE_ALLOCATED, m.allocatedBytes()); + EXPECT_EQ(5 * sizeof(int) + BASE_USED, m.usedBytes()); EXPECT_EQ(0 * sizeof(int), m.deadBytes()); EXPECT_EQ(5 * sizeof(int), m.allocatedBytesOnHold()); s.reclaim_memory(101); @@ -492,28 +493,29 @@ TEST(DataStoreTest, require_that_memory_usage_is_calculated) TEST(DataStoreTest, require_that_we_can_disable_elemement_hold_list) { - constexpr size_t BASE = 676; + constexpr size_t BASE_ALLOCATED = 4228; + constexpr size_t BASE_USED = 308; MyStore s; MyRef r1 = s.addEntry(10); MyRef r2 = s.addEntry(20); MyRef r3 = s.addEntry(30); (void) r3; vespalib::MemoryUsage m = s.getMemoryUsage(); - EXPECT_EQ(MyRef::offsetSize() * sizeof(int) + BASE, m.allocatedBytes()); - EXPECT_EQ(4 * sizeof(int) + BASE, m.usedBytes()); + EXPECT_EQ(MyRef::offsetSize() * sizeof(int) + BASE_ALLOCATED, m.allocatedBytes()); + EXPECT_EQ(4 * sizeof(int) + BASE_USED, m.usedBytes()); EXPECT_EQ(1 * sizeof(int), m.deadBytes()); EXPECT_EQ(0 * sizeof(int), m.allocatedBytesOnHold()); s.holdElem(r1, 1); m = s.getMemoryUsage(); - EXPECT_EQ(MyRef::offsetSize() * sizeof(int) + BASE, m.allocatedBytes()); - EXPECT_EQ(4 * sizeof(int) + BASE, m.usedBytes()); + EXPECT_EQ(MyRef::offsetSize() * sizeof(int) + BASE_ALLOCATED, m.allocatedBytes()); + EXPECT_EQ(4 * sizeof(int) + BASE_USED, m.usedBytes()); EXPECT_EQ(1 * sizeof(int), m.deadBytes()); EXPECT_EQ(1 * sizeof(int), m.allocatedBytesOnHold()); s.disableElemHoldList(); s.holdElem(r2, 1); m = s.getMemoryUsage(); - EXPECT_EQ(MyRef::offsetSize() * sizeof(int) + BASE, m.allocatedBytes()); - EXPECT_EQ(4 * sizeof(int) + BASE, m.usedBytes()); + EXPECT_EQ(MyRef::offsetSize() * sizeof(int) + BASE_ALLOCATED, m.allocatedBytes()); + EXPECT_EQ(4 * sizeof(int) + BASE_USED, m.usedBytes()); EXPECT_EQ(2 * sizeof(int), m.deadBytes()); EXPECT_EQ(1 * sizeof(int), m.allocatedBytesOnHold()); s.assign_generation(100); @@ -538,7 +540,7 @@ void assertGrowStats(GrowthStats expSizes, TEST(DataStoreTest, require_that_buffer_growth_works) { - constexpr size_t BASE = 41032u; + constexpr size_t BASE = 10312; // Always switch to new buffer, min size 4 assertGrowStats({ 4, 4, 4, 4, 8, 16, 16, 32, 64, 64 }, { 4 }, 20 + BASE, 4, 0); diff --git a/vespalib/src/tests/datastore/unique_store/unique_store_test.cpp b/vespalib/src/tests/datastore/unique_store/unique_store_test.cpp index cf62d238d53..1781a680bac 100644 --- a/vespalib/src/tests/datastore/unique_store/unique_store_test.cpp +++ b/vespalib/src/tests/datastore/unique_store/unique_store_test.cpp @@ -470,14 +470,14 @@ TEST_F(DoubleTest, nan_is_handled) } TEST_F(DoubleTest, control_memory_usage) { - EXPECT_EQ(464, sizeof(store)); + EXPECT_EQ(456u, sizeof(store)); EXPECT_EQ(144u, sizeof(BufferState)); - EXPECT_EQ(163908u, store.get_values_memory_usage().allocatedBytes()); - EXPECT_EQ(163892u, store.get_values_memory_usage().usedBytes()); - EXPECT_EQ(262120u, store.get_dictionary_memory_usage().allocatedBytes()); - EXPECT_EQ(164176u, store.get_dictionary_memory_usage().usedBytes()); - EXPECT_EQ(426028u, store.getMemoryUsage().allocatedBytes()); - EXPECT_EQ(328068u, store.getMemoryUsage().usedBytes()); + EXPECT_EQ(28740u, store.get_values_memory_usage().allocatedBytes()); + EXPECT_EQ(24804u, store.get_values_memory_usage().usedBytes()); + EXPECT_EQ(126952u, store.get_dictionary_memory_usage().allocatedBytes()); + EXPECT_EQ(25248u, store.get_dictionary_memory_usage().usedBytes()); + EXPECT_EQ(155692u, store.getMemoryUsage().allocatedBytes()); + EXPECT_EQ(50052, store.getMemoryUsage().usedBytes()); } GTEST_MAIN_RUN_ALL_TESTS() diff --git a/vespalib/src/vespa/vespalib/datastore/array_store.h b/vespalib/src/vespa/vespalib/datastore/array_store.h index dd786e5f2e2..c2b65d72f03 100644 --- a/vespalib/src/vespa/vespalib/datastore/array_store.h +++ b/vespalib/src/vespa/vespalib/datastore/array_store.h @@ -76,10 +76,9 @@ public: return ConstArrayRef(); } RefT internalRef(ref); - uint32_t typeId = _store.getTypeId(internalRef.bufferId()); - if (typeId != _largeArrayTypeId) [[likely]] { - size_t arraySize = _mapper.get_array_size(typeId); - return getSmallArray(internalRef, arraySize); + const BufferAndMeta & bufferAndMeta = _store.getBufferMeta(internalRef.bufferId()); + if (bufferAndMeta.getTypeId() != _largeArrayTypeId) [[likely]] { + return getSmallArray(internalRef, bufferAndMeta.getArraySize()); } else { return getLargeArray(internalRef); } diff --git a/vespalib/src/vespa/vespalib/datastore/buffer_free_list.cpp b/vespalib/src/vespa/vespalib/datastore/buffer_free_list.cpp index 0a440e3e867..224ed4b0c8f 100644 --- a/vespalib/src/vespa/vespalib/datastore/buffer_free_list.cpp +++ b/vespalib/src/vespa/vespalib/datastore/buffer_free_list.cpp @@ -52,5 +52,23 @@ BufferFreeList::disable() _free_list = nullptr; } +void +BufferFreeList::push_entry(EntryRef ref) { + if (empty()) { + attach(); + } + _free_refs.push_back(ref); +} +EntryRef +BufferFreeList::pop_entry() { + EntryRef ret = _free_refs.back(); + _free_refs.pop_back(); + if (empty()) { + detach(); + } + _dead_elems.store(_dead_elems.load(std::memory_order_relaxed) - _array_size, std::memory_order_relaxed); + return ret; +} + } diff --git a/vespalib/src/vespa/vespalib/datastore/buffer_free_list.h b/vespalib/src/vespa/vespalib/datastore/buffer_free_list.h index 74fd47056de..148ddd8db88 100644 --- a/vespalib/src/vespa/vespalib/datastore/buffer_free_list.h +++ b/vespalib/src/vespa/vespalib/datastore/buffer_free_list.h @@ -41,21 +41,8 @@ public: bool enabled() const { return _free_list != nullptr; } bool empty() const { return _free_refs.empty(); } uint32_t array_size() const { return _array_size; } - void push_entry(EntryRef ref) { - if (empty()) { - attach(); - } - _free_refs.push_back(ref); - } - EntryRef pop_entry() { - EntryRef ret = _free_refs.back(); - _free_refs.pop_back(); - if (empty()) { - detach(); - } - _dead_elems.store(_dead_elems.load(std::memory_order_relaxed) - _array_size, std::memory_order_relaxed); - return ret; - } + void push_entry(EntryRef ref); + EntryRef pop_entry(); }; } diff --git a/vespalib/src/vespa/vespalib/datastore/bufferstate.cpp b/vespalib/src/vespa/vespalib/datastore/bufferstate.cpp index 45a94693eeb..47fba1ef697 100644 --- a/vespalib/src/vespa/vespalib/datastore/bufferstate.cpp +++ b/vespalib/src/vespa/vespalib/datastore/bufferstate.cpp @@ -171,7 +171,7 @@ BufferState::dropBuffer(uint32_t buffer_id, std::atomic<void*>& buffer) } void -BufferState::disableElemHoldList() +BufferState::disable_elem_hold_list() { _disableElemHoldList = true; } diff --git a/vespalib/src/vespa/vespalib/datastore/bufferstate.h b/vespalib/src/vespa/vespalib/datastore/bufferstate.h index aa7f6dfdfa4..c3e6110cc52 100644 --- a/vespalib/src/vespa/vespalib/datastore/bufferstate.h +++ b/vespalib/src/vespa/vespalib/datastore/bufferstate.h @@ -86,7 +86,7 @@ public: * Disable hold of elements, just mark elements as dead without cleanup. * Typically used when tearing down data structure in a controlled manner. */ - void disableElemHoldList(); + void disable_elem_hold_list(); /** * Update stats to reflect that the given elements are put on hold. @@ -134,23 +134,28 @@ public: class BufferAndMeta { public: - BufferAndMeta() : BufferAndMeta(nullptr, 0, 0) { } - BufferAndMeta(void* buffer, uint32_t typeId, uint32_t arraySize) - : _buffer(buffer), - _typeId(typeId), - _arraySize(arraySize) - { } + BufferAndMeta() : BufferAndMeta(nullptr, nullptr, 0, 0) { } std::atomic<void*>& get_atomic_buffer() noexcept { return _buffer; } void* get_buffer_relaxed() noexcept { return _buffer.load(std::memory_order_relaxed); } const void* get_buffer_acquire() const noexcept { return _buffer.load(std::memory_order_acquire); } uint32_t getTypeId() const { return _typeId; } uint32_t getArraySize() const { return _arraySize; } + BufferState * get_state_relaxed() { return _state.load(std::memory_order_relaxed); } + const BufferState * get_state_acquire() const { return _state.load(std::memory_order_acquire); } void setTypeId(uint32_t typeId) { _typeId = typeId; } void setArraySize(uint32_t arraySize) { _arraySize = arraySize; } + void set_state(BufferState * state) { _state.store(state, std::memory_order_release); } private: - std::atomic<void*> _buffer; - uint32_t _typeId; - uint32_t _arraySize; + BufferAndMeta(void* buffer, BufferState * state, uint32_t typeId, uint32_t arraySize) + : _buffer(buffer), + _state(state), + _typeId(typeId), + _arraySize(arraySize) + { } + std::atomic<void*> _buffer; + std::atomic<BufferState*> _state; + uint32_t _typeId; + uint32_t _arraySize; }; } diff --git a/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp b/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp index 99bdb19576f..a40aa713bca 100644 --- a/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp +++ b/vespalib/src/vespa/vespalib/datastore/datastorebase.cpp @@ -84,16 +84,17 @@ DataStoreBase::DataStoreBase(uint32_t numBuffers, uint32_t offset_bits, size_t m : _entry_ref_hold_list(), _buffers(numBuffers), _primary_buffer_ids(), - _states(numBuffers), + _stash(), _typeHandlers(), _free_lists(), _compaction_count(0u), _genHolder(), _maxArrays(maxArrays), - _numBuffers(numBuffers), - _offset_bits(offset_bits), + _bufferIdLimit(0u), _hold_buffer_count(0u), + _offset_bits(offset_bits), _freeListsEnabled(false), + _disableElemHoldList(false), _initializing(false) { } @@ -107,7 +108,7 @@ void DataStoreBase::switch_primary_buffer(uint32_t typeId, size_t elemsNeeded) { size_t buffer_id = getFirstFreeBufferId(); - if ((buffer_id < _states.size()) && !getBufferState(buffer_id).isFree()) { + if (buffer_id >= getMaxNumBuffers()) { LOG_ABORT(vespalib::make_string("switch_primary_buffer(%u, %zu): did not find a free buffer", typeId, elemsNeeded).c_str()); } @@ -159,19 +160,24 @@ DataStoreBase::consider_grow_active_buffer(uint32_t type_id, size_t elems_needed uint32_t DataStoreBase::getFirstFreeBufferId() { - for (uint32_t buffer_id = 0; buffer_id < _states.size(); buffer_id++) { - if (getBufferState(buffer_id).isFree()) { + uint32_t buffer_id = 0; + for (auto & buffer : _buffers) { + BufferState * state = buffer.get_state_relaxed(); + if (state == nullptr || state->isFree()) { return buffer_id; } + buffer_id++; } - // Need next(new) buffer - return _states.size(); + // No free buffer, return out of bounds + return buffer_id; } BufferState & DataStoreBase::getBufferState(uint32_t buffer_id) noexcept { - assert(buffer_id < _states.size()); - return _states[buffer_id]; + assert(buffer_id < get_bufferid_limit_relaxed()); + BufferState * state = _buffers[buffer_id].get_state_relaxed(); + assert(state != nullptr); + return *state; } void @@ -202,7 +208,7 @@ DataStoreBase::init_primary_buffers() uint32_t numTypes = _primary_buffer_ids.size(); for (uint32_t typeId = 0; typeId < numTypes; ++typeId) { size_t buffer_id = getFirstFreeBufferId(); - assert((buffer_id == _states.size()) || getBufferState(buffer_id).isFree()); + assert(buffer_id <= get_bufferid_limit_relaxed()); onActive(buffer_id, typeId, 0u); _primary_buffer_ids[typeId] = buffer_id; } @@ -253,9 +259,12 @@ DataStoreBase::reclaim_all_memory() void DataStoreBase::dropBuffers() { - uint32_t numBuffers = _buffers.size(); - for (uint32_t bufferId = 0; bufferId < numBuffers; ++bufferId) { - getBufferState(bufferId).dropBuffer(bufferId, _buffers[bufferId].get_atomic_buffer()); + uint32_t buffer_id_limit = get_bufferid_limit_relaxed(); + for (uint32_t bufferId = 0; bufferId < buffer_id_limit; ++bufferId) { + BufferAndMeta & buffer = _buffers[bufferId]; + BufferState * state = buffer.get_state_relaxed(); + assert(state != nullptr); + state->dropBuffer(bufferId, buffer.get_atomic_buffer()); } _genHolder.reclaim_all(); } @@ -278,18 +287,17 @@ DataStoreBase::getMemoryUsage() const { size_t extra_allocated = 0; extra_allocated += _buffers.capacity() * sizeof(BufferAndMeta); extra_allocated += _primary_buffer_ids.capacity() * sizeof(uint32_t); - extra_allocated += _states.capacity() * sizeof(BufferState); extra_allocated += _typeHandlers.capacity() * sizeof(BufferTypeBase *); extra_allocated += _free_lists.capacity() * sizeof(FreeList); size_t extra_used = 0; extra_used += _buffers.size() * sizeof(BufferAndMeta); extra_used += _primary_buffer_ids.size() * sizeof(uint32_t); - extra_used += _states.size() * sizeof(BufferState); extra_used += _typeHandlers.size() * sizeof(BufferTypeBase *); extra_used += _free_lists.size() * sizeof(FreeList); usage.incAllocatedBytes(extra_allocated); usage.incUsedBytes(extra_used); + usage.merge(_stash.get_memory_usage()); return usage; } @@ -305,41 +313,27 @@ DataStoreBase::holdBuffer(uint32_t bufferId) void DataStoreBase::enableFreeLists() { - for (auto& bState : _states) { - if (!bState.isActive() || bState.getCompacting()) { - continue; - } - bState.enable_free_list(_free_lists[bState.getTypeId()]); - } + for_each_buffer([this](BufferState & state) { + if (!state.isActive() || state.getCompacting()) return; + state.enable_free_list(_free_lists[state.getTypeId()]); + }); _freeListsEnabled = true; } void DataStoreBase::disableFreeLists() { - for (auto& bState : _states) { - bState.disable_free_list(); - } + for_each_buffer([](BufferState & state) { state.disable_free_list(); }); _freeListsEnabled = false; } void -DataStoreBase::enableFreeList(uint32_t bufferId) -{ - BufferState &state = getBufferState(bufferId); - if (_freeListsEnabled && state.isActive() && !state.getCompacting()) { - state.enable_free_list(_free_lists[state.getTypeId()]); - } -} - -void DataStoreBase::disableElemHoldList() { - for (auto &state : _states) { - if (!state.isFree()) { - state.disableElemHoldList(); - } - } + for_each_buffer([](BufferState & state) { + if (!state.isFree()) state.disable_elem_hold_list(); + }); + _disableElemHoldList = true; } MemoryStats @@ -347,19 +341,23 @@ DataStoreBase::getMemStats() const { MemoryStats stats; - for (const auto& bState: _states) { - auto typeHandler = bState.getTypeHandler(); - auto state = bState.getState(); + uint32_t buffer_id_limit = get_bufferid_limit_acquire(); + stats._freeBuffers = (getMaxNumBuffers() - buffer_id_limit); + for (uint32_t bufferId = 0; bufferId < buffer_id_limit; ++bufferId) { + const BufferState * bState = _buffers[bufferId].get_state_acquire(); + assert(bState != nullptr); + auto typeHandler = bState->getTypeHandler(); + auto state = bState->getState(); if ((state == BufferState::State::FREE) || (typeHandler == nullptr)) { ++stats._freeBuffers; } else if (state == BufferState::State::ACTIVE) { size_t elementSize = typeHandler->elementSize(); ++stats._activeBuffers; - bState.stats().add_to_mem_stats(elementSize, stats); + bState->stats().add_to_mem_stats(elementSize, stats); } else if (state == BufferState::State::HOLD) { size_t elementSize = typeHandler->elementSize(); ++stats._holdBuffers; - bState.stats().add_to_mem_stats(elementSize, stats); + bState->stats().add_to_mem_stats(elementSize, stats); } else { LOG_ABORT("should not be reached"); } @@ -374,21 +372,24 @@ DataStoreBase::getMemStats() const vespalib::AddressSpace DataStoreBase::getAddressSpaceUsage() const { + uint32_t buffer_id_limit = get_bufferid_limit_acquire(); size_t usedArrays = 0; size_t deadArrays = 0; - size_t limitArrays = 0; - for (const auto& bState: _states) { - if (bState.isActive()) { - uint32_t arraySize = bState.getArraySize(); - usedArrays += bState.size() / arraySize; - deadArrays += bState.stats().dead_elems() / arraySize; - limitArrays += bState.capacity() / arraySize; - } else if (bState.isOnHold()) { - uint32_t arraySize = bState.getArraySize(); - usedArrays += bState.size() / arraySize; - limitArrays += bState.capacity() / arraySize; - } else if (bState.isFree()) { + size_t limitArrays = size_t(_maxArrays) * (getMaxNumBuffers() - buffer_id_limit); + for (uint32_t bufferId = 0; bufferId < buffer_id_limit; ++bufferId) { + const BufferState * bState = _buffers[bufferId].get_state_acquire(); + assert(bState != nullptr); + if (bState->isFree()) { limitArrays += _maxArrays; + } else if (bState->isActive()) { + uint32_t arraySize = bState->getArraySize(); + usedArrays += bState->size() / arraySize; + deadArrays += bState->stats().dead_elems() / arraySize; + limitArrays += bState->capacity() / arraySize; + } else if (bState->isOnHold()) { + uint32_t arraySize = bState->getArraySize(); + usedArrays += bState->size() / arraySize; + limitArrays += bState->capacity() / arraySize; } else { LOG_ABORT("should not be reached"); } @@ -400,13 +401,29 @@ void DataStoreBase::onActive(uint32_t bufferId, uint32_t typeId, size_t elemsNeeded) { assert(typeId < _typeHandlers.size()); - assert(bufferId < _numBuffers); - BufferState &state = getBufferState(bufferId); + assert(bufferId <= _bufferIdLimit); + BufferAndMeta & bufferMeta = _buffers[bufferId]; - state.onActive(bufferId, typeId, _typeHandlers[typeId], elemsNeeded, bufferMeta.get_atomic_buffer()); + BufferState *state = bufferMeta.get_state_relaxed(); + if (state == nullptr) { + BufferState & newState = _stash.create<BufferState>(); + if (_disableElemHoldList) { + newState.disable_elem_hold_list(); + } + if ( ! _freeListsEnabled) { + newState.disable_free_list(); + } + state = & newState; + bufferMeta.set_state(state); + _bufferIdLimit.store(bufferId + 1, std::memory_order_release); + } + assert(state->isFree()); + state->onActive(bufferId, typeId, _typeHandlers[typeId], elemsNeeded, bufferMeta.get_atomic_buffer()); bufferMeta.setTypeId(typeId); - bufferMeta.setArraySize(state.getArraySize()); - enableFreeList(bufferId); + bufferMeta.setArraySize(state->getArraySize()); + if (_freeListsEnabled && state->isActive() && !state->getCompacting()) { + state->enable_free_list(_free_lists[state->getTypeId()]); + } } void @@ -448,7 +465,7 @@ DataStoreBase::markCompacting(uint32_t bufferId) } assert(!state.getCompacting()); state.setCompacting(); - state.disableElemHoldList(); + state.disable_elem_hold_list(); state.disable_free_list(); inc_compaction_count(); } @@ -456,39 +473,41 @@ DataStoreBase::markCompacting(uint32_t bufferId) std::unique_ptr<CompactingBuffers> DataStoreBase::start_compact_worst_buffers(CompactionSpec compaction_spec, const CompactionStrategy& compaction_strategy) { + uint32_t buffer_id_limit = get_bufferid_limit_relaxed(); // compact memory usage - CompactBufferCandidates elem_buffers(_numBuffers, compaction_strategy.get_max_buffers(), + CompactBufferCandidates elem_buffers(buffer_id_limit, compaction_strategy.get_max_buffers(), compaction_strategy.get_active_buffers_ratio(), compaction_strategy.getMaxDeadBytesRatio() / 2, CompactionStrategy::DEAD_BYTES_SLACK); // compact address space - CompactBufferCandidates array_buffers(_numBuffers, compaction_strategy.get_max_buffers(), + CompactBufferCandidates array_buffers(buffer_id_limit, compaction_strategy.get_max_buffers(), compaction_strategy.get_active_buffers_ratio(), compaction_strategy.getMaxDeadAddressSpaceRatio() / 2, CompactionStrategy::DEAD_ADDRESS_SPACE_SLACK); - uint32_t free_buffers = _buffers.size() - _states.size(); - for (uint32_t bufferId = 0; bufferId < _numBuffers; ++bufferId) { - const auto &state = getBufferState(bufferId); - if (state.isActive()) { - auto typeHandler = state.getTypeHandler(); + uint32_t free_buffers = getMaxNumBuffers() - buffer_id_limit; + for (uint32_t bufferId = 0; bufferId < buffer_id_limit; ++bufferId) { + BufferState * state = _buffers[bufferId].get_state_relaxed(); + assert(state != nullptr); + if (state->isFree()) { + free_buffers++; + } else if (state->isActive()) { + auto typeHandler = state->getTypeHandler(); uint32_t arraySize = typeHandler->getArraySize(); uint32_t reservedElements = typeHandler->getReservedElements(bufferId); - size_t used_elems = state.size(); - size_t deadElems = state.stats().dead_elems() - reservedElements; + size_t used_elems = state->size(); + size_t deadElems = state->stats().dead_elems() - reservedElements; if (compaction_spec.compact_memory()) { elem_buffers.add(bufferId, used_elems, deadElems); } if (compaction_spec.compact_address_space()) { - array_buffers.add(bufferId, used_elems / arraySize, deadElems / arraySize); + array_buffers.add(bufferId, used_elems / arraySize, deadElems / arraySize); } - } else if (state.isFree()) { - ++free_buffers; } } elem_buffers.set_free_buffers(free_buffers); array_buffers.set_free_buffers(free_buffers); std::vector<uint32_t> result; - result.reserve(std::min(_numBuffers, 2 * compaction_strategy.get_max_buffers())); + result.reserve(std::min(buffer_id_limit, 2 * compaction_strategy.get_max_buffers())); elem_buffers.select(result); array_buffers.select(result); std::sort(result.begin(), result.end()); @@ -497,7 +516,7 @@ DataStoreBase::start_compact_worst_buffers(CompactionSpec compaction_spec, const for (auto buffer_id : result) { markCompacting(buffer_id); } - return std::make_unique<CompactingBuffers>(*this, _numBuffers, _offset_bits, std::move(result)); + return std::make_unique<CompactingBuffers>(*this, buffer_id_limit, _offset_bits, std::move(result)); } void diff --git a/vespalib/src/vespa/vespalib/datastore/datastorebase.h b/vespalib/src/vespa/vespalib/datastore/datastorebase.h index 8749f2a27e6..ecbac451c5a 100644 --- a/vespalib/src/vespa/vespalib/datastore/datastorebase.h +++ b/vespalib/src/vespa/vespalib/datastore/datastorebase.h @@ -8,9 +8,8 @@ #include <vespa/vespalib/util/address_space.h> #include <vespa/vespalib/util/generationholder.h> #include <vespa/vespalib/util/generation_hold_list.h> -#include <vespa/vespalib/util/memoryusage.h> +#include <vespa/vespalib/util/stash.h> #include <atomic> -#include <deque> #include <vector> namespace vespalib::datastore { @@ -75,7 +74,20 @@ public: uint32_t primary_buffer_id(uint32_t typeId) const { return _primary_buffer_ids[typeId]; } BufferState &getBufferState(uint32_t buffer_id) noexcept; const BufferAndMeta & getBufferMeta(uint32_t buffer_id) const { return _buffers[buffer_id]; } - uint32_t getNumBuffers() const { return _numBuffers; } + uint32_t getMaxNumBuffers() const noexcept { return _buffers.size(); } + uint32_t get_bufferid_limit_acquire() const noexcept { return _bufferIdLimit.load(std::memory_order_acquire); } + uint32_t get_bufferid_limit_relaxed() noexcept { return _bufferIdLimit.load(std::memory_order_relaxed); } + + template<typename FuncType> + void for_each_active_buffer(FuncType func) { + uint32_t buffer_id_limit = get_bufferid_limit_relaxed(); + for (uint32_t i = 0; i < buffer_id_limit; i++) { + const BufferState * state = _buffers[i].get_state_relaxed(); + if (state && state->isActive()) { + func(i, *state); + } + } + } /** * Assign generation on data elements on hold lists added since the last time this function was called. @@ -218,11 +230,7 @@ private: * Hold of buffer has ended. */ void doneHoldBuffer(uint32_t bufferId); - /** - * Enable free list management. - * This only works for fixed size elements. - */ - void enableFreeList(uint32_t bufferId); + /** * Switch buffer state to active for the given buffer. * @@ -236,24 +244,33 @@ private: void fallbackResize(uint32_t bufferId, size_t elementsNeeded); uint32_t getFirstFreeBufferId(); + template<typename FuncType> + void for_each_buffer(FuncType func) { + uint32_t buffer_id_limit = get_bufferid_limit_relaxed(); + for (uint32_t i = 0; i < buffer_id_limit; i++) { + func(*(_buffers[i].get_state_relaxed())); + } + } + virtual void reclaim_all_entry_refs() = 0; - std::vector<BufferAndMeta> _buffers; // For fast mapping with known types + std::vector<BufferAndMeta> _buffers; // For fast mapping with known types // Provides a mapping from typeId -> primary buffer for that type. // The primary buffer is used for allocations of new element(s) if no available slots are found in free lists. std::vector<uint32_t> _primary_buffer_ids; - std::vector<BufferState> _states; + Stash _stash; std::vector<BufferTypeBase *> _typeHandlers; // TypeId -> handler std::vector<FreeList> _free_lists; mutable std::atomic<uint64_t> _compaction_count; vespalib::GenerationHolder _genHolder; const uint32_t _maxArrays; - const uint32_t _numBuffers; - const uint32_t _offset_bits; + std::atomic<uint32_t> _bufferIdLimit; uint32_t _hold_buffer_count; + const uint8_t _offset_bits; bool _freeListsEnabled; + bool _disableElemHoldList; bool _initializing; }; diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store.hpp b/vespalib/src/vespa/vespalib/datastore/unique_store.hpp index aef6ea07290..52b0798543f 100644 --- a/vespalib/src/vespa/vespalib/datastore/unique_store.hpp +++ b/vespalib/src/vespa/vespalib/datastore/unique_store.hpp @@ -102,8 +102,8 @@ private: std::unique_ptr<CompactingBuffers> _compacting_buffers; void allocMapping() { - _mapping.resize(RefT::numBuffers()); auto& data_store = _compacting_buffers->get_store(); + _mapping.resize(data_store.get_bufferid_limit_relaxed()); for (const auto bufferId : _compacting_buffers->get_buffer_ids()) { BufferState &state = data_store.getBufferState(bufferId); _mapping[bufferId].resize(state.get_used_arrays()); diff --git a/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.hpp b/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.hpp index 6d08a027bf1..32513d09c72 100644 --- a/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.hpp +++ b/vespalib/src/vespa/vespalib/datastore/unique_store_enumerator.hpp @@ -42,13 +42,10 @@ template <typename RefT> void UniqueStoreEnumerator<RefT>::allocate_enum_values(DataStoreBase & store) { - _enumValues.resize(RefType::numBuffers()); - for (uint32_t bufferId = 0; bufferId < RefType::numBuffers(); ++bufferId) { - const BufferState &state = store.getBufferState(bufferId); - if (state.isActive()) { - _enumValues[bufferId].resize(state.get_used_arrays()); - } - } + _enumValues.resize(store.get_bufferid_limit_relaxed()); + store.for_each_active_buffer([this](uint32_t buffer_id, const BufferState & state) { + _enumValues[buffer_id].resize(state.get_used_arrays()); + }); } template <typename RefT> |