summaryrefslogtreecommitdiffstats
path: root/vdslib/src/tests/container/documentlisttest.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'vdslib/src/tests/container/documentlisttest.cpp')
-rw-r--r--vdslib/src/tests/container/documentlisttest.cpp538
1 files changed, 538 insertions, 0 deletions
diff --git a/vdslib/src/tests/container/documentlisttest.cpp b/vdslib/src/tests/container/documentlisttest.cpp
new file mode 100644
index 00000000000..60d01a63c1b
--- /dev/null
+++ b/vdslib/src/tests/container/documentlisttest.cpp
@@ -0,0 +1,538 @@
+// Copyright 2016 Yahoo Inc. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+
+#include <vespa/fastos/fastos.h>
+#include <vespa/vdslib/container/writabledocumentlist.h>
+
+#include <cppunit/extensions/HelperMacros.h>
+#include <vespa/document/base/testdocman.h>
+#include <vespa/document/config/config-documenttypes.h>
+#include <vespa/document/fieldvalue/document.h>
+#include <vespa/document/repo/documenttyperepo.h>
+#include <vespa/document/update/assignvalueupdate.h>
+#include <vespa/document/update/documentupdate.h>
+#include <vespa/vespalib/objects/nbostream.h>
+#include <vespa/vespalib/util/random.h>
+#include <vespa/vespalib/util/vstringfmt.h>
+#include <iostream>
+
+using document::DocumentTypeRepo;
+using document::readDocumenttypesConfig;
+using vespalib::nbostream;
+
+namespace vdslib {
+
+struct WritableDocumentListTest : public CppUnit::TestFixture {
+
+ void testSimple();
+ void testAlignedWriting();
+ void testSizeOf();
+ void testReadJavaFile();
+ void testGetSerializedSize();
+ void testCopyEntry();
+ void testOperationList();
+ void testSetTimestamp();
+ void testDifferentBuckets();
+
+ CPPUNIT_TEST_SUITE(WritableDocumentListTest);
+ CPPUNIT_TEST(testSimple);
+ CPPUNIT_TEST(testAlignedWriting);
+ CPPUNIT_TEST(testSizeOf);
+ CPPUNIT_TEST(testReadJavaFile);
+ CPPUNIT_TEST(testGetSerializedSize);
+ CPPUNIT_TEST(testCopyEntry);
+ CPPUNIT_TEST(testOperationList);
+ CPPUNIT_TEST(testSetTimestamp);
+ CPPUNIT_TEST(testDifferentBuckets);
+ CPPUNIT_TEST_SUITE_END();
+};
+
+CPPUNIT_TEST_SUITE_REGISTRATION(WritableDocumentListTest);
+
+void WritableDocumentListTest::testDifferentBuckets()
+{
+ document::TestDocMan docman;
+ std::vector<char> buffer(1024);
+ WritableDocumentList block(docman.getTypeRepoSP(), &buffer[0], buffer.size());
+
+ std::unique_ptr<document::Document> doc1 = docman.createDocument("This is a test", "userdoc:test:1234:1");
+ block.addPut(*doc1);
+
+ std::unique_ptr<document::Document> doc2 = docman.createDocument("This is a test", "userdoc:test:4567:1");
+ try {
+ block.addPut(*doc2);
+ CPPUNIT_ASSERT(false);
+ } catch (...) {
+ }
+
+ block.addRemove(document::DocumentId("userdoc:test:1234:2"));
+
+ try {
+ block.addRemove(document::DocumentId("userdoc:test:4567:2"));
+ CPPUNIT_ASSERT(false);
+ } catch (...) {
+ }
+}
+
+void WritableDocumentListTest::testSimple()
+{
+ document::TestDocMan docman;
+ std::vector<char> buffer(1024);
+ std::vector<document::Document::SP > docs;
+ for (uint32_t i=1; i<10; ++i) {
+ docs.push_back(document::Document::SP(
+ docman.createDocument("This is a test",
+ vespalib::make_string("userdoc:test:123456789:%d", i)
+ ).release()));
+ }
+
+ WritableDocumentList block(docman.getTypeRepoSP(), &buffer[0], buffer.size());
+ // begin() should now equal start()
+ CPPUNIT_ASSERT(block.begin() == block.end());
+ // Add docs in the easy way.
+ block.addPut(*docs[0]);
+ block.addRemove(docs[1]->getId());
+ block.addPut(*docs[2], 0xfee1deadbabeb00bull);
+
+ // Add the way slotfile will.
+ WritableDocumentList::MetaEntry entry;
+ entry.timestamp = 1234;
+ entry.headerPos = 0;
+ nbostream stream;
+ docs[3]->serializeHeader(stream);
+ entry.headerLen = stream.size();
+ entry.bodyPos = entry.headerLen;
+ stream.clear();
+ docs[3]->serializeBody(stream);
+ entry.bodyLen = stream.size();
+ entry.flags = 0;
+
+ CPPUNIT_ASSERT(block.countFree() > entry.headerLen + entry.bodyLen
+ + sizeof(WritableDocumentList::MetaEntry));
+ char *pos = block.prepareMultiput(1, entry.headerLen + entry.bodyLen);
+ CPPUNIT_ASSERT(pos != 0);
+ document::ByteBuffer bb(pos, entry.headerLen + entry.bodyLen);
+ docs[3]->serializeHeader(bb);
+ docs[3]->serializeBody(bb);
+ std::vector<WritableDocumentList::MetaEntry> entries;
+ entries.push_back(entry);
+ block.commitMultiput(entries, pos);
+
+ // Copy buffer someplace else to simulate serialize/deserialize
+ std::vector<char> copy(buffer);
+
+ // Get documents out again. Verify correctness..
+ {
+ WritableDocumentList::const_iterator it = block.begin();
+ // First document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+
+ std::unique_ptr<document::Document> doc(it->getDocument());
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(*docs[0], *doc);
+
+ CPPUNIT_ASSERT(++it != block.end());
+ // First document deleted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(docs[1]->getId(), doc->getId());
+ CPPUNIT_ASSERT(++it != block.end());
+ // Second document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0xfee1deadbabeb00bull,
+ it->getTimestamp());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(*docs[2], *doc);
+ CPPUNIT_ASSERT(++it != block.end());
+ // Third document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)1234, it->getTimestamp());
+
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(*docs[3], *doc);
+ CPPUNIT_ASSERT(++it == block.end());
+ }
+
+ // Test downsizing
+ CPPUNIT_ASSERT_EQUAL(621u, block.countFree());
+ uint32_t requiredSize = block.getBufferSize() - block.countFree();
+ std::vector<char> otherBuffer(requiredSize);
+ DocumentList otherBlock(block, &otherBuffer[0], otherBuffer.size());
+ CPPUNIT_ASSERT_EQUAL(403u, otherBlock.getBufferSize());
+ // Get documents out again of other block. Verify correctness..
+ {
+ DocumentList::const_iterator it = otherBlock.begin();
+ // First document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+
+ std::unique_ptr<document::Document> doc(it->getDocument());
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(*docs[0], *doc);
+
+ CPPUNIT_ASSERT(++it != block.end());
+ // First document deleted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ CPPUNIT_ASSERT_EQUAL(docs[1]->getId(), doc->getId());
+ CPPUNIT_ASSERT(++it != block.end());
+ // Second document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0xfee1deadbabeb00bull, it->getTimestamp());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+ CPPUNIT_ASSERT_EQUAL(*docs[2], *doc);
+ CPPUNIT_ASSERT(++it != block.end());
+ // Third document putted
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)1234, it->getTimestamp());
+
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+ CPPUNIT_ASSERT_EQUAL(*docs[3], *doc);
+ CPPUNIT_ASSERT(++it == block.end());
+ }
+
+ // begin() should equal start() after clear
+ block.clear();
+ CPPUNIT_ASSERT(block.begin() == block.end());
+}
+
+void WritableDocumentListTest::testSetTimestamp()
+{
+ document::TestDocMan docman;
+ std::vector<char> buffer(1024);
+
+ WritableDocumentList block(docman.getTypeRepoSP(), &buffer[0], buffer.size());
+ // begin() should now equal start()
+ CPPUNIT_ASSERT(block.begin() == block.end());
+ // Add docs in the easy way.
+ std::unique_ptr<document::Document> doc(
+ docman.createDocument("This is a test",
+ vespalib::make_string("userdoc:test:123456789:t")));
+
+ block.addPut(*doc);
+
+ CPPUNIT_ASSERT(block.begin() != block.end());
+
+ block.begin()->setTimestamp(1234);
+
+ CPPUNIT_ASSERT_EQUAL((Timestamp)1234, block.begin()->getTimestamp());
+}
+
+void WritableDocumentListTest::testAlignedWriting()
+{
+ document::TestDocMan docman;
+ vespalib::RandomGen randomizer(5123);
+ std::vector<char> buffer(1024*1024);
+
+ std::vector<document::Document::SP > docs;
+ for (uint32_t i=1; i<10; ++i) {
+ docs.push_back(document::Document::SP(
+ docman.createDocument("Aligned writing test blaaaah",
+ vespalib::make_string("userdoc:test:123456789:%d", i)
+ ).release()));
+ }
+
+ WritableDocumentList block(docman.getTypeRepoSP(), &buffer[0], buffer.size());
+
+ // Add documents aligned the way slotfile will.
+ for (uint32_t i=1; i<50; ++i) {
+ std::vector<WritableDocumentList::MetaEntry> entries;
+ uint32_t currentPos = 0;
+ for (uint32_t j=0, n=randomizer.nextUint32(1,10); j<n; ++j) {
+ WritableDocumentList::MetaEntry entry;
+ entry.timestamp = i * 1000 + j;
+ entry.headerPos = currentPos;
+ entry.headerLen = randomizer.nextUint32(5, 50);
+ entry.bodyPos = currentPos + entry.headerLen;
+ entry.bodyLen = randomizer.nextUint32(0, 4000);
+ entry.flags = 0;
+ currentPos += entry.headerLen + entry.bodyLen;
+ entries.push_back(entry);
+ }
+ currentPos += 512 - (currentPos % 512);
+ CPPUNIT_ASSERT(currentPos % 512 == 0);
+
+ CPPUNIT_ASSERT(block.countFree() > currentPos + entries.size()
+ * sizeof(WritableDocumentList::MetaEntry));
+ char *pos = block.prepareMultiput(entries.size(), currentPos);
+ CPPUNIT_ASSERT(pos != 0);
+ CPPUNIT_ASSERT((pos - &buffer[0]) % 512 == 0);
+ block.commitMultiput(entries, pos);
+ }
+}
+
+void WritableDocumentListTest::testSizeOf()
+{
+ CPPUNIT_ASSERT_EQUAL(size_t(32), sizeof(WritableDocumentList::MetaEntry));
+
+ std::string buffercont("This is a buffer of data we will create meta "
+ " entry from to verify binary compability");
+ std::vector<char> buffer(buffercont.begin(), buffercont.end());
+ CPPUNIT_ASSERT(buffer.size() > sizeof(WritableDocumentList::MetaEntry));
+
+ WritableDocumentList::MetaEntry* e(reinterpret_cast<WritableDocumentList::MetaEntry*>(&buffer[0]));
+
+ CPPUNIT_ASSERT_EQUAL(Timestamp(2338328219631577172ull), e->timestamp);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(1969365089), e->headerPos);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(1919247974), e->headerLen);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(543584032), e->bodyPos);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(1635017060), e->bodyLen);
+ CPPUNIT_ASSERT_EQUAL(uint32_t(32), uint32_t(e->flags));
+}
+
+void WritableDocumentListTest::testReadJavaFile()
+{
+ DocumentTypeRepo::SP repo(new DocumentTypeRepo(readDocumenttypesConfig(
+ "../test/files/documenttypes.cfg")));
+
+ //read file
+ int file = open("../test/files/documentlist-java.dat", O_RDONLY);
+ if (file == -1) {
+ CPPUNIT_ASSERT(0);
+ }
+
+ uint32_t len = lseek(file, 0, SEEK_END);
+ lseek(file, 0, SEEK_SET);
+
+ vespalib::MallocPtr data(len);
+ CPPUNIT_ASSERT_EQUAL((ssize_t) len, read(file, data, len));
+ close(file);
+
+
+ //create documentlist
+ DocumentList block(repo, data.str(), len, true);
+
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 4, block.size());
+
+ DocumentList::const_iterator it = block.begin();
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT(!it->isBodyStripped());
+ CPPUNIT_ASSERT(!it->isUpdateEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+ std::unique_ptr<document::Document> doc(it->getDocument());
+ CPPUNIT_ASSERT(doc.get());
+ CPPUNIT_ASSERT_EQUAL(document::DocumentId("userdoc:foo:99999999:1"),
+ doc->getId());
+ vespalib::string foo = "foo";
+ CPPUNIT_ASSERT_EQUAL(foo, doc->getValue("headerstring")->getAsString());
+
+ CPPUNIT_ASSERT(++it != block.end());
+
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(it->isRemoveEntry());
+ CPPUNIT_ASSERT(!it->isBodyStripped());
+ CPPUNIT_ASSERT(!it->isUpdateEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+ CPPUNIT_ASSERT_EQUAL(document::DocumentId("userdoc:foo:99999999:2"),
+ doc->getId());
+
+ CPPUNIT_ASSERT(++it != block.end());
+
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT(!it->isBodyStripped());
+ CPPUNIT_ASSERT(!it->isUpdateEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+ CPPUNIT_ASSERT_EQUAL(document::DocumentId("userdoc:foo:99999999:3"),
+ doc->getId());
+ CPPUNIT_ASSERT_EQUAL(5.5f, doc->getValue("bodyfloat")->getAsFloat());
+
+ CPPUNIT_ASSERT(++it != block.end());
+
+ CPPUNIT_ASSERT(it->valid());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ CPPUNIT_ASSERT(!it->isBodyStripped());
+ CPPUNIT_ASSERT(it->isUpdateEntry());
+ CPPUNIT_ASSERT_EQUAL((uint64_t)0, it->getTimestamp());
+ document::DocumentUpdate::UP docUp = it->getUpdate();
+ CPPUNIT_ASSERT(docUp.get());
+ const document::AssignValueUpdate* valUp = dynamic_cast<const document::AssignValueUpdate*>(docUp->getUpdates().front().getUpdates().front().get());
+ vespalib::string ballooooo = "ballooooo";
+ CPPUNIT_ASSERT_EQUAL(ballooooo, valUp->getValue().getAsString());
+
+ CPPUNIT_ASSERT(++it == block.end());
+}
+
+void WritableDocumentListTest::testGetSerializedSize() {
+ document::TestDocMan docman;
+ std::vector<char> buffer(1024);
+ std::vector<document::Document::SP > docs;
+ for (uint32_t i=1; i<3; ++i) {
+ docs.push_back(document::Document::SP(
+ docman.createDocument("This is a test, blah bloh bluh blih",
+ vespalib::make_string("userdoc:test:1298798789:%d", i)
+ ).release()));
+ }
+ WritableDocumentList block(docman.getTypeRepoSP(), &buffer[0], buffer.size());
+ // begin() should now equal start()
+ CPPUNIT_ASSERT(block.begin() == block.end());
+ // Add docs in the easy way.
+ block.addPut(*docs[0]);
+ block.addRemove(docs[1]->getId());
+
+ WritableDocumentList::const_iterator it = block.begin();
+ CPPUNIT_ASSERT_EQUAL((const uint32_t)(docs[0]->serialize()->getLength()
+ + sizeof(DocumentList::MetaEntry)),
+ it->getSerializedSize());
+}
+
+void WritableDocumentListTest::testCopyEntry() {
+ DocumentTypeRepo::SP repo(new DocumentTypeRepo(readDocumenttypesConfig(
+ "../test/files/documenttypes.cfg")));
+
+ //read file
+ int file = open("../test/files/documentlist-java.dat", O_RDONLY);
+ if (file == -1) {
+ CPPUNIT_ASSERT(0);
+ }
+
+ uint32_t len = lseek(file, 0, SEEK_END);
+ lseek(file, 0, SEEK_SET);
+
+ vespalib::MallocPtr data(len);
+ CPPUNIT_ASSERT_EQUAL((ssize_t) len, read(file, data, len));
+ close(file);
+
+
+ //create documentlist
+ DocumentList block(repo, data.str(), len, true);
+
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 4, block.size());
+
+ //create a writabledocumentlist
+ std::vector<char> buffer(1024);
+ WritableDocumentList wrBlock(repo, &buffer[0], buffer.size());
+
+ DocumentList::const_iterator it = block.begin();
+ wrBlock.addEntry(*it);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 1, wrBlock.size());
+
+ ++it;
+ wrBlock.addEntry(*it);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 2, wrBlock.size());
+
+ ++it;
+ wrBlock.addEntry(*it);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 3, wrBlock.size());
+
+ ++it;
+ wrBlock.addEntry(*it);
+ CPPUNIT_ASSERT_EQUAL((uint32_t) 4, wrBlock.size());
+
+
+ it = block.begin();
+ DocumentList::const_iterator wrIt = wrBlock.begin();
+
+ //test equality of first entry
+ CPPUNIT_ASSERT_EQUAL(it->getFlags(), wrIt->getFlags());
+ std::unique_ptr<document::Document> doc(it->getDocument());
+ CPPUNIT_ASSERT(doc.get());
+
+ std::unique_ptr<document::Document> wrDoc(wrIt->getDocument());
+ CPPUNIT_ASSERT(wrDoc.get());
+ CPPUNIT_ASSERT_EQUAL(*doc, *wrDoc);
+
+ ++it;
+ ++wrIt;
+
+ //test equality of second entry
+ CPPUNIT_ASSERT_EQUAL(it->getFlags(), wrIt->getFlags());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ wrDoc = wrIt->getDocument();
+ CPPUNIT_ASSERT(wrDoc.get());
+ CPPUNIT_ASSERT_EQUAL(*doc, *wrDoc);
+
+ ++it;
+ ++wrIt;
+
+ //test equality of third entry
+ CPPUNIT_ASSERT_EQUAL(it->getFlags(), wrIt->getFlags());
+ doc = it->getDocument();
+ CPPUNIT_ASSERT(doc.get());
+
+ wrDoc = wrIt->getDocument();
+ CPPUNIT_ASSERT(wrDoc.get());
+ CPPUNIT_ASSERT_EQUAL(*doc, *wrDoc);
+
+ ++it;
+ ++wrIt;
+
+ //test equality of fourth entry
+ CPPUNIT_ASSERT_EQUAL(it->getFlags(), wrIt->getFlags());
+ document::DocumentUpdate::UP docUp = it->getUpdate();
+ CPPUNIT_ASSERT(docUp.get());
+
+ document::DocumentUpdate::UP wrDocUp = wrIt->getUpdate();
+ CPPUNIT_ASSERT(wrDocUp.get());
+ CPPUNIT_ASSERT_EQUAL(docUp->getId(), wrDocUp->getId());
+}
+
+void WritableDocumentListTest::testOperationList()
+{
+ document::TestDocMan docman;
+ OperationList ol;
+ for (uint32_t i=0; i<3000; ++i) {
+ ol.addPut(docman.createDocument(
+ "This is a test, blah bloh bluh blih",
+ vespalib::make_string("userdoc:test:1298798789:%d", i)));
+ }
+
+ for (uint32_t i=5000; i<5900; ++i) {
+ ol.addRemove(document::DocumentId(
+ vespalib::make_string("userdoc:test:1298798789:%d", i)));
+ }
+
+ std::vector<char> buf(ol.getRequiredBufferSize());
+
+ MutableDocumentList mdl(docman.getTypeRepoSP(), &(buf[0]), buf.size());
+ mdl.addOperationList(ol);
+
+ DocumentList::const_iterator it = mdl.begin();
+
+ for (uint32_t i=0; i<3000; ++i, it++) {
+ CPPUNIT_ASSERT_EQUAL(
+ vespalib::make_vespa_string("userdoc:test:1298798789:%d", i),
+ it->getDocument()->getId().toString());
+ CPPUNIT_ASSERT(!it->isRemoveEntry());
+ }
+
+ for (uint32_t i=5000; i<5900; ++i, it++) {
+ CPPUNIT_ASSERT_EQUAL(
+ vespalib::make_vespa_string("userdoc:test:1298798789:%d", i),
+ it->getDocument()->getId().toString());
+ CPPUNIT_ASSERT(it->isRemoveEntry());
+ }
+}
+
+}