1 | |
---|
2 | #include "ps_database.hxx" |
---|
3 | |
---|
4 | using namespace std; |
---|
5 | |
---|
6 | void PS_Database::reinit(const char *_name, bool _readonly) { |
---|
7 | if (db_file) { |
---|
8 | db_file->reinit(_name, _readonly); |
---|
9 | } |
---|
10 | else { |
---|
11 | db_file = new PS_FileBuffer(_name, _readonly); |
---|
12 | } |
---|
13 | db_name2id_map.clear(); |
---|
14 | db_id2name_map.clear(); |
---|
15 | if (!db_rootnode.isNull()) db_rootnode.setNull(); |
---|
16 | db_rootnode = new PS_Node(-1); |
---|
17 | } |
---|
18 | |
---|
19 | void PS_Database::readMappings(PS_FileBuffer *_file, ID2NameMap &_id2name_map, Name2IDMap &_name2id_map) { |
---|
20 | char *buffer = (char *)malloc(_file->BUFFER_SIZE); |
---|
21 | // read number of species |
---|
22 | unsigned long int number_of_species = 0; |
---|
23 | _file->get_ulong(number_of_species); |
---|
24 | // read mappings |
---|
25 | for (unsigned long int i = 0; i < number_of_species; ++i) { |
---|
26 | // read id |
---|
27 | SpeciesID id; |
---|
28 | _file->get(&id, sizeof(SpeciesID)); |
---|
29 | // read name |
---|
30 | unsigned int length_of_name; |
---|
31 | _file->get_uint(length_of_name); |
---|
32 | _file->get(buffer, length_of_name); |
---|
33 | // store in mappings |
---|
34 | string name(buffer, length_of_name); |
---|
35 | _id2name_map[id] = name; |
---|
36 | _name2id_map[name] = id; |
---|
37 | } |
---|
38 | free(buffer); |
---|
39 | } |
---|
40 | |
---|
41 | void PS_Database::writeMappings(PS_FileBuffer *_file, ID2NameMap &_id2name_map) { |
---|
42 | // write number of species |
---|
43 | _file->put_ulong(_id2name_map.size()); |
---|
44 | // write mappings |
---|
45 | for (ID2NameMapCIter i = _id2name_map.begin(); i != _id2name_map.end(); ++i) { |
---|
46 | // write id |
---|
47 | _file->put(&(i->first), sizeof(SpeciesID)); |
---|
48 | // write name |
---|
49 | unsigned int length_of_name = i->second.size(); |
---|
50 | _file->put_uint(length_of_name); |
---|
51 | _file->put(i->second.c_str(), length_of_name); |
---|
52 | } |
---|
53 | } |
---|
54 | |
---|
55 | void PS_Database::readTree(PS_FileBuffer *_file) { |
---|
56 | if (!db_rootnode.isNull()) db_rootnode.setNull(); // discard old tree |
---|
57 | db_rootnode = new PS_Node(-1); |
---|
58 | db_rootnode->load(_file); |
---|
59 | } |
---|
60 | |
---|
61 | void PS_Database::writeTree(PS_FileBuffer *_file) { |
---|
62 | if (db_rootnode.isNull()) return; // no tree, no write |
---|
63 | db_rootnode->save(_file); |
---|
64 | } |
---|
65 | |
---|
66 | bool PS_Database::readHeader(PS_FileBuffer *_file) { |
---|
67 | char *buffer = (char *) malloc(FILE_ID.size()); |
---|
68 | _file->get(buffer, FILE_ID.size()); |
---|
69 | bool file_ok = (FILE_ID.compare(buffer) == 0); |
---|
70 | if (buffer) free(buffer); |
---|
71 | return file_ok; |
---|
72 | } |
---|
73 | |
---|
74 | void PS_Database::writeHeader(PS_FileBuffer *_file) { |
---|
75 | _file->put(FILE_ID.c_str(), FILE_ID.size()); |
---|
76 | } |
---|
77 | |
---|
78 | void PS_Database::callback(void *_caller) { |
---|
79 | // |
---|
80 | // return if node has no probes |
---|
81 | // |
---|
82 | if (!((PS_Node *)_caller)->hasProbes()) return; |
---|
83 | |
---|
84 | // |
---|
85 | // convert IDs from file to DB-IDs |
---|
86 | // |
---|
87 | IDSet path; |
---|
88 | PS_NodePtr current_node = db_path; |
---|
89 | while (current_node->hasChildren()) { |
---|
90 | // get next node in path |
---|
91 | pair<bool, PS_NodePtr> child = current_node->getChild(0); |
---|
92 | ps_assert(child.first); |
---|
93 | current_node = child.second; |
---|
94 | // get ID from node |
---|
95 | SpeciesID id = current_node->getNum(); |
---|
96 | // store ID in ID-Set |
---|
97 | ID2IDMapCIter db_id = db_file2db_id_map.find(id); |
---|
98 | path.insert((db_id == db_file2db_id_map.end()) ? id : db_id->second); |
---|
99 | } |
---|
100 | |
---|
101 | // |
---|
102 | // assert path |
---|
103 | // |
---|
104 | current_node = db_rootnode; |
---|
105 | for (IDSetCIter id=path.begin(); id != path.end(); ++id) { |
---|
106 | current_node = current_node->assertChild(*id); |
---|
107 | } |
---|
108 | |
---|
109 | // |
---|
110 | // append probes |
---|
111 | // |
---|
112 | current_node->addProbes(((PS_Node *)_caller)->getProbesBegin(), ((PS_Node *)_caller)->getProbesEnd()); |
---|
113 | } |
---|
114 | |
---|
115 | bool PS_Database::merge(const char *_other_db_name) { |
---|
116 | // |
---|
117 | // read other DB's mappings |
---|
118 | // |
---|
119 | PS_FileBuffer *other_db_file = new PS_FileBuffer(_other_db_name, PS_FileBuffer::READONLY); |
---|
120 | Name2IDMap other_name2id_map; |
---|
121 | ID2NameMap other_id2name_map; |
---|
122 | |
---|
123 | if (!readHeader(other_db_file)) return false; // not a file i wrote |
---|
124 | readMappings(other_db_file, other_id2name_map, other_name2id_map); |
---|
125 | |
---|
126 | // |
---|
127 | // get next assignable ID from highest used ID in mappings |
---|
128 | // |
---|
129 | SpeciesID next_usable_ID = (db_id2name_map.rbegin()->first > other_id2name_map.rbegin()->first) ? db_id2name_map.rbegin()->first + 1 : other_id2name_map.rbegin()->first + 1; |
---|
130 | |
---|
131 | // |
---|
132 | // iterate over DB names |
---|
133 | // |
---|
134 | db_file2db_id_map.clear(); |
---|
135 | for (Name2IDMapCIter i=db_name2id_map.begin(); i != db_name2id_map.end(); ++i) { |
---|
136 | // lookup name in other mapping |
---|
137 | Name2IDMapIter other_i = other_name2id_map.find(i->first); |
---|
138 | |
---|
139 | // if name not in other mapping |
---|
140 | if (other_i == other_name2id_map.end()) { |
---|
141 | // lookup ID in other mapping |
---|
142 | ID2NameMapIter other_i2 = other_id2name_map.find(i->second); |
---|
143 | |
---|
144 | // if ID is used for other name in other_mappings |
---|
145 | if (other_i2 != other_id2name_map.end()) { |
---|
146 | // lookup other name in DB mapping |
---|
147 | Name2IDMapIter i2 = db_name2id_map.find(other_i2->second); |
---|
148 | |
---|
149 | // if other name is not in DB mapping |
---|
150 | if (i2 == db_name2id_map.end()) { |
---|
151 | // store file->DB ID mapping |
---|
152 | db_file2db_id_map[other_i2->first] = next_usable_ID; |
---|
153 | ++next_usable_ID; |
---|
154 | // erase handled name |
---|
155 | other_name2id_map.erase(other_i2->second); |
---|
156 | } |
---|
157 | } |
---|
158 | } |
---|
159 | // if name in other mapping with different ID |
---|
160 | else if (other_i->second != i->second) { |
---|
161 | // store file->DB ID mapping |
---|
162 | db_file2db_id_map[other_i->second] = i->second; |
---|
163 | // erase handled name |
---|
164 | other_name2id_map.erase(other_i); |
---|
165 | } |
---|
166 | // if name in other mapping with same ID |
---|
167 | else { |
---|
168 | // erase handled name |
---|
169 | other_name2id_map.erase(other_i); |
---|
170 | } |
---|
171 | } |
---|
172 | |
---|
173 | // |
---|
174 | // iterate over remaining file names |
---|
175 | // |
---|
176 | for (Name2IDMapCIter other_i=other_name2id_map.begin(); other_i != other_name2id_map.end(); ++other_i) { |
---|
177 | db_file2db_id_map[other_i->second] = next_usable_ID; |
---|
178 | ++next_usable_ID; |
---|
179 | } |
---|
180 | db_MAX_ID = next_usable_ID-1; |
---|
181 | |
---|
182 | // append tree if mappings are equal |
---|
183 | if (db_file2db_id_map.empty()) { |
---|
184 | return db_rootnode->append(other_db_file); |
---|
185 | } |
---|
186 | // merge in tree if mappings differ |
---|
187 | else { |
---|
188 | if (db_path.isNull()) db_path = new PS_Node(-1); |
---|
189 | return db_path->read(other_db_file, this); |
---|
190 | } |
---|
191 | } |
---|