File: osmium_dump_internal.cpp

package info (click to toggle)
libosmium 2.15.1-1
  • links: PTS, VCS
  • area: main
  • in suites: buster
  • size: 4,108 kB
  • sloc: cpp: 46,496; sh: 148; makefile: 20
file content (202 lines) | stat: -rw-r--r-- 6,550 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
/*

  EXAMPLE osmium_dump_internal

  Reads an OSM file and dumps the internal datastructure to disk including
  indexes to find objects and object relations.

  Note that this example programm will only work with small and medium sized
  OSM files, not with the planet.

  You can use the osmium_index example program to inspect the indexes.

  DEMONSTRATES USE OF:
  * file input
  * indexes and maps
  * use of the DiskStore handler
  * use of the ObjectRelations handler

  SIMPLER EXAMPLES you might want to understand first:
  * osmium_read
  * osmium_count
  * osmium_road_length
  * osmium_location_cache_create
  * osmium_location_cache_use

  LICENSE
  The code in this example file is released into the Public Domain.

*/

#include <cerrno>      // for errno
#include <cstdlib>     // for std::exit
#include <cstring>     // for std::strerror
#include <iostream>    // for std::cout, std::cerr
#include <string>      // for std::string
#include <sys/stat.h>  // for open
#include <sys/types.h> // for open

#ifdef _WIN32
# include <io.h>       // for _setmode
#endif

#ifdef _MSC_VER
# include <direct.h>
#endif

// Allow any format of input files (XML, PBF, ...)
#include <osmium/io/any_input.hpp>

// The DiskStore handler
#include <osmium/handler/disk_store.hpp>

// The ObjectRelations handler
#include <osmium/handler/object_relations.hpp>

// The indexes
#include <osmium/index/map/sparse_mem_array.hpp>
#include <osmium/index/multimap/sparse_mem_array.hpp>

using offset_index_type = osmium::index::map::SparseMemArray<osmium::unsigned_object_id_type, size_t>;
using map_type = osmium::index::multimap::SparseMemArray<osmium::unsigned_object_id_type, osmium::unsigned_object_id_type>;

/**
 * Small class wrapping index files, basically making sure errors are handled
 * and the files are closed on destruction.
 */
class IndexFile {

    int m_fd;

public:

    explicit IndexFile(const std::string& filename) :
        m_fd(::open(filename.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666)) { // NOLINT(hicpp-signed-bitwise)
        if (m_fd < 0) {
            std::cerr << "Can't open index file '" << filename << "': " << std::strerror(errno) << "\n";
            std::exit(2);
        }
#ifdef _WIN32
        _setmode(m_fd, _O_BINARY);
#endif
    }

    IndexFile(const IndexFile&) = delete;
    IndexFile& operator=(const IndexFile&) = delete;

    IndexFile(IndexFile&&) = delete;
    IndexFile& operator=(IndexFile&&) = delete;

    ~IndexFile() {
        if (m_fd >= 0) {
            close(m_fd);
        }
    }

    int fd() const noexcept {
        return m_fd;
    }

}; // class IndexFile

int main(int argc, char* argv[]) {
    if (argc != 3) {
        std::cerr << "Usage: " << argv[0] << " OSMFILE DIR\n";
        std::exit(2);
    }

    try {
        const std::string input_file_name{argv[1]};
        const std::string output_dir{argv[2]};

        // Create output directory. Ignore the error if it already exists.
#ifndef _WIN32
        const int result = ::mkdir(output_dir.c_str(), 0777);
#else
        const int result = mkdir(output_dir.c_str());
#endif
        if (result == -1 && errno != EEXIST) {
            std::cerr << "Problem creating directory '" << output_dir << "': " << std::strerror(errno) << "\n";
            std::exit(2);
        }

        // Create the output file which will contain our serialized OSM data
        const std::string data_file{output_dir + "/data.osm.ser"};
        const int data_fd = ::open(data_file.c_str(), O_WRONLY | O_CREAT | O_TRUNC, 0666); // NOLINT(hicpp-signed-bitwise)
        if (data_fd < 0) {
            std::cerr << "Can't open data file '" << data_file << "': " << std::strerror(errno) << "\n";
            std::exit(2);
        }

#ifdef _WIN32
        _setmode(data_fd, _O_BINARY);
#endif

        // These indexes store the offset in the data file where each node, way,
        // or relation is stored.
        offset_index_type node_index;
        offset_index_type way_index;
        offset_index_type relation_index;

        // This handler will dump the internal data to disk using the given file
        // descriptor while updating the indexes.
        osmium::handler::DiskStore disk_store_handler{data_fd, node_index, way_index, relation_index};

        // These indexes store the mapping from node id to the ids of the ways
        // containing this node, and from node/way/relation ids to the ids of the
        // relations containing those objects.
        map_type map_node2way;
        map_type map_node2relation;
        map_type map_way2relation;
        map_type map_relation2relation;

        // This handler will update the map indexes.
        osmium::handler::ObjectRelations object_relations_handler{map_node2way, map_node2relation, map_way2relation, map_relation2relation};

        // Read OSM data buffer by buffer.
        osmium::io::Reader reader{input_file_name};

        while (osmium::memory::Buffer buffer = reader.read()) {
            // Write buffer to disk and update indexes.
            disk_store_handler(buffer);

            // Update object relation index maps.
            osmium::apply(buffer, object_relations_handler);
        }

        reader.close();

        // Write out node, way, and relation offset indexes to disk.
        IndexFile nodes_idx{output_dir + "/nodes.idx"};
        node_index.dump_as_list(nodes_idx.fd());

        IndexFile ways_idx{output_dir + "/ways.idx"};
        way_index.dump_as_list(ways_idx.fd());

        IndexFile relations_idx{output_dir + "/relations.idx"};
        relation_index.dump_as_list(relations_idx.fd());

        // Sort the maps (so later binary search will work on them) and write
        // them to disk.
        map_node2way.sort();
        IndexFile node2way_idx{output_dir + "/node2way.map"};
        map_node2way.dump_as_list(node2way_idx.fd());

        map_node2relation.sort();
        IndexFile node2relation_idx{output_dir + "/node2rel.map"};
        map_node2relation.dump_as_list(node2relation_idx.fd());

        map_way2relation.sort();
        IndexFile way2relation_idx{output_dir + "/way2rel.map"};
        map_way2relation.dump_as_list(way2relation_idx.fd());

        map_relation2relation.sort();
        IndexFile relation2relation_idx{output_dir + "/rel2rel.map"};
        map_relation2relation.dump_as_list(relation2relation_idx.fd());
    } catch (const std::exception& e) {
        // All exceptions used by the Osmium library derive from std::exception.
        std::cerr << e.what() << '\n';
        std::exit(1);
    }
}