1 #include "catch.hpp" 2 3 #include <osmium/builder/attr.hpp> 4 #include <osmium/storage/item_stash.hpp> 5 6 #include <sstream> 7 #include <string> 8 #include <vector> 9 generate_test_data()10osmium::memory::Buffer generate_test_data() { 11 using namespace osmium::builder::attr; // NOLINT(google-build-using-namespace) 12 13 osmium::memory::Buffer buffer{1024UL * 1024UL, osmium::memory::Buffer::auto_grow::yes}; 14 15 const osmium::object_id_type num_nodes = 100; 16 const osmium::object_id_type num_ways = 50; 17 const osmium::object_id_type num_relations = 30; 18 19 osmium::object_id_type id = 1; 20 for (; id <= num_nodes; ++id) { 21 osmium::builder::add_node(buffer, _id(id)); 22 } 23 24 for (; id <= num_nodes + num_ways; ++id) { 25 osmium::builder::add_way(buffer, _id(id)); 26 } 27 28 for (; id <= num_nodes + num_ways + num_relations; ++id) { 29 osmium::builder::add_relation(buffer, _id(id)); 30 } 31 32 return buffer; 33 } 34 35 36 TEST_CASE("Item stash handle") { 37 const auto handle = osmium::ItemStash::handle_type{}; 38 REQUIRE_FALSE(handle.valid()); 39 40 std::stringstream ss; 41 ss << handle; 42 REQUIRE(ss.str() == "-"); 43 } 44 45 TEST_CASE("Item stash") { 46 const auto buffer = generate_test_data(); 47 48 osmium::ItemStash stash; 49 REQUIRE(stash.size() == 0); 50 REQUIRE(stash.count_removed() == 0); 51 52 std::vector<osmium::ItemStash::handle_type> handles; 53 for (const auto& item : buffer) { 54 auto handle = stash.add_item(item); 55 handles.push_back(handle); 56 } 57 58 REQUIRE(stash.size() == 180); 59 REQUIRE(stash.count_removed() == 0); 60 61 REQUIRE(stash.used_memory() > 1024UL * 1024UL); 62 63 osmium::object_id_type id = 1; 64 for (auto& handle : handles) { // must be reference because we will change it! 65 REQUIRE(handle.valid()); 66 const auto& item = stash.get_item(handle); 67 bool correct_type = item.type() == osmium::item_type::node || 68 item.type() == osmium::item_type::way || 69 item.type() == osmium::item_type::relation; 70 REQUIRE(correct_type); 71 const auto& obj = static_cast<const osmium::OSMObject&>(item); 72 REQUIRE(obj.id() == id); 73 74 std::stringstream ss; 75 ss << handle; 76 REQUIRE(ss.str() == std::to_string(id)); 77 78 if (obj.id() % 3 == 0) { 79 stash.remove_item(handle); 80 handle = osmium::ItemStash::handle_type{}; 81 } 82 83 ++id; 84 } 85 86 REQUIRE(stash.size() == 120); 87 REQUIRE(stash.count_removed() == 60); 88 89 id = 1; 90 int count_valid = 0; 91 int count_invalid = 0; 92 for (auto handle : handles) { 93 if (handle.valid()) { 94 ++count_valid; 95 const auto& item = stash.get_item(handle); 96 const bool correct_type = item.type() == osmium::item_type::node || 97 item.type() == osmium::item_type::way || 98 item.type() == osmium::item_type::relation; 99 REQUIRE(correct_type); 100 const auto& obj = static_cast<const osmium::OSMObject&>(item); 101 REQUIRE(obj.id() == id); 102 } else { 103 ++count_invalid; 104 } 105 ++id; 106 } 107 108 REQUIRE(count_valid == 120); 109 REQUIRE(count_invalid == 60); 110 111 stash.garbage_collect(); 112 REQUIRE(stash.size() == 120); 113 REQUIRE(stash.count_removed() == 0); 114 115 id = 1; 116 for (auto handle : handles) { 117 if (handle.valid()) { 118 const auto& item = stash.get_item(handle); 119 const bool correct_type = item.type() == osmium::item_type::node || 120 item.type() == osmium::item_type::way || 121 item.type() == osmium::item_type::relation; 122 REQUIRE(correct_type); 123 const auto& obj = static_cast<const osmium::OSMObject&>(item); 124 REQUIRE(obj.id() == id); 125 } 126 ++id; 127 } 128 129 stash.clear(); 130 REQUIRE(stash.size() == 0); 131 REQUIRE(stash.count_removed() == 0); 132 } 133 134 TEST_CASE("Fill item stash until it garbage collects") { 135 const auto buffer = generate_test_data(); 136 137 osmium::ItemStash stash; 138 REQUIRE(stash.size() == 0); 139 REQUIRE(stash.count_removed() == 0); 140 141 const auto& node = buffer.get<osmium::Node>(0); 142 143 std::vector<osmium::ItemStash::handle_type> handles; 144 std::size_t num_items = 6UL * 1000UL * 1000UL; 145 for (std::size_t i = 0; i < num_items; ++i) { 146 auto handle = stash.add_item(node); 147 handles.push_back(handle); 148 } 149 150 REQUIRE(stash.size() == num_items); 151 REQUIRE(stash.count_removed() == 0); 152 153 for (std::size_t i = 0; i < num_items; ++i) { 154 if (i % 10 != 0) { 155 stash.remove_item(handles[i]); 156 } 157 } 158 159 REQUIRE(stash.size() == num_items / 10); 160 REQUIRE(stash.count_removed() == num_items / 10 * 9); 161 162 // trigger compaction 163 stash.add_item(node); 164 165 REQUIRE(stash.size() == num_items / 10 + 1); 166 REQUIRE(stash.count_removed() == 0); 167 } 168 169