1 #include <iostream>
2 #include <sstream>
3 #include "boxm2_lru_cache1.h"
4 //:
5 // \file
6 #include <boxm2/boxm2_block_metadata.h>
7 #ifdef _MSC_VER
8 # include "vcl_msvc_warnings.h"
9 #endif
10
11 //: PUBLIC create method, for creating singleton instance of boxm2_cache1
create(const boxm2_scene_sptr & scene,BOXM2_IO_FS_TYPE fs_type)12 void boxm2_lru_cache1::create(const boxm2_scene_sptr& scene, BOXM2_IO_FS_TYPE fs_type)
13 {
14 if (boxm2_cache1::exists())
15 {
16 if(boxm2_cache1::instance_->get_scene()->xml_path() == scene->xml_path())
17 {
18 std::cout << "boxm2_lru_cache1:: boxm2_cache1 singleton already created" << std::endl;
19 }
20 else
21 {
22 std::cout << "boxm2_lru_cache1:: destroying current cache and creating new one: " << scene->data_path() << std::endl;
23 instance_ = new boxm2_lru_cache1(scene, fs_type);
24 }
25 }
26 else {
27 instance_ = new boxm2_lru_cache1(scene, fs_type);
28 }
29 }
30
31 //: constructor, set the directory path
boxm2_lru_cache1(const boxm2_scene_sptr & scene,BOXM2_IO_FS_TYPE fs_type)32 boxm2_lru_cache1::boxm2_lru_cache1(const boxm2_scene_sptr& scene, BOXM2_IO_FS_TYPE fs_type) : boxm2_cache1(scene,fs_type)
33 {
34 scene_dir_ = scene->data_path();
35 }
36
37 //: destructor flushes the memory for currently ongoing asynchronous requests
~boxm2_lru_cache1()38 boxm2_lru_cache1::~boxm2_lru_cache1()
39 {
40 // save the data and delete
41 for (auto & iter : cached_data_)
42 {
43 for (auto it = iter.second.begin(); it != iter.second.end(); it++) {
44 boxm2_block_id id = it->first;
45 #if 0 // Currently causing some blocks to not save
46 if (!it->second->read_only_) {
47 boxm2_sio_mgr::save_block_data_base(scene_dir_, it->first, it->second, iter->first);
48 }
49 #endif
50 // now throw it away
51 delete it->second;
52 }
53 iter.second.clear();
54 }
55
56 for (auto & cached_block : cached_blocks_)
57 {
58 boxm2_block_id id = cached_block.first;
59 #if 0 // Currently causing some blocks to not save
60 if (!iter->second->read_only())
61 boxm2_sio_mgr::save_block(scene_dir_, iter->second);
62 #endif
63 delete cached_block.second;
64 }
65 }
66
67 //: delete all the memory
68 // Caution: make sure to call write to disk methods not to loose writable data
clear_cache()69 void boxm2_lru_cache1::clear_cache()
70 {
71 // delete
72 for (auto & iter : cached_data_)
73 {
74 for (auto it = iter.second.begin(); it != iter.second.end(); it++)
75 delete it->second;
76 iter.second.clear();
77 }
78 cached_data_.clear();
79
80 for (auto & cached_block : cached_blocks_)
81 delete cached_block.second;
82 cached_blocks_.clear();
83 }
84
85 //: realization of abstract "get_block(block_id)"
get_block(boxm2_block_id id)86 boxm2_block* boxm2_lru_cache1::get_block(boxm2_block_id id)
87 {
88 boxm2_block_metadata data = scene_->get_block_metadata(id);
89
90 // then look for the block you're requesting
91 if ( cached_blocks_.find(id) != cached_blocks_.end() )
92 {
93 #ifdef DEBUG
94 std::cout<<"CACHE HIT :)"<<std::endl;
95 #endif
96 return cached_blocks_[id];
97 }
98
99 #ifdef DEBUG
100 std::cout<<"Cache miss :("<<std::endl;
101 #endif
102 // otherwise load it from disk with blocking and update cache
103 boxm2_block* loaded = boxm2_sio_mgr::load_block(scene_dir_, id, data, filesystem_);
104
105 // if the block is null then initialize an empty one
106 if (!loaded && scene_->block_exists(id)) {
107 std::cout<<"boxm2_lru_cache1::initializing empty block "<<id<<std::endl;
108
109 loaded = new boxm2_block(data);
110 }
111
112 // update cache before returning the block
113 cached_blocks_[id] = loaded;
114 return loaded;
115 }
116
117 //: get data by type and id
get_data_base(boxm2_block_id id,std::string type,std::size_t num_bytes,bool read_only)118 boxm2_data_base* boxm2_lru_cache1::get_data_base(boxm2_block_id id, std::string type, std::size_t num_bytes, bool read_only)
119 {
120 // grab a reference to the map of cached_data_
121 std::map<boxm2_block_id, boxm2_data_base*>& data_map =
122 this->cached_data_map(type);
123
124 // then look for the block you're requesting
125 auto iter = data_map.find(id);
126 if ( iter != data_map.end() )
127 {
128 // congrats you've found the data block in cache, update cache and return block
129 if (!read_only) // write-enable is enforced
130 iter->second->enable_write();
131 return iter->second;
132 }
133
134 // grab from disk
135 boxm2_data_base* loaded = boxm2_sio_mgr::load_block_data_generic(scene_dir_, id, type, filesystem_);
136 boxm2_block_metadata data = scene_->get_block_metadata(id);
137
138 // if num_bytes is greater than zero, then you're guaranteed to return a data size with that many bytes
139 if (num_bytes > 0) {
140 // if loaded from disk is good and it matches size, you found it, return
141 if (loaded && loaded->buffer_length()==num_bytes) {
142 // update data map
143 data_map[id] = loaded;
144 if (!read_only) // write-enable is enforced
145 loaded->enable_write();
146 return loaded;
147 }
148
149 // requesting a specific number of bytes, and not found it on disk
150 std::cout<<"boxm2_lru_cache1::initializing empty data "<<id
151 <<" type: "<<type
152 <<" to size: "<<num_bytes<<" bytes"<<std::endl;
153 loaded = new boxm2_data_base(new char[num_bytes], num_bytes, id, read_only);
154 loaded->set_default_value(type, data);
155 }
156 else {
157 // otherwise it's a miss, load sync from disk, update cache
158 // loaded = boxm2_sio_mgr::load_block_data_generic(scene_dir_, id, type, filesystem_);
159 if (!loaded && scene_->block_exists(id)) {
160 std::cout<<"boxm2_lru_cache1::initializing empty data "<<id<<" type: "<<type<<std::endl;
161 loaded = new boxm2_data_base(data, type, read_only);
162 }
163 }
164
165 // update data map
166 data_map[id] = loaded;
167 if(!read_only)
168 loaded->enable_write();
169 return loaded;
170 }
171
172 //: returns a data_base pointer which is initialized to the default value of the type.
173 // If a block for this type exists on the cache, it is removed and replaced with the new one.
174 // This method does not check whether a block of this type already exists on the disk nor writes it to the disk
get_data_base_new(boxm2_block_id id,std::string type,std::size_t num_bytes,bool read_only)175 boxm2_data_base* boxm2_lru_cache1::get_data_base_new(boxm2_block_id id, std::string type, std::size_t num_bytes, bool read_only)
176 {
177 boxm2_data_base* block_data;
178 if (num_bytes > 0) {
179 boxm2_block_metadata data = scene_->get_block_metadata(id);
180 // requesting a specific number of bytes,
181 //std::cout<<"boxm2_lru_cache1::initializing empty data "<<id
182 // <<" type: "<<type
183 // <<" to size: "<<num_bytes<<" bytes"<<std::endl;
184 std::cout<<id<<" init empty "<<type<<std::endl;
185 block_data = new boxm2_data_base(new char[num_bytes], num_bytes, id, read_only);
186 block_data->set_default_value(type, data);
187 }
188 else {
189 // initialize an empty block
190 //std::cout<<"boxm2_lru_cache1::initializing empty data "<<id<<" type: "<<type<<std::endl;
191 std::cout<<id<<" init empty "<<type<<std::endl;
192 boxm2_block_metadata data = scene_->get_block_metadata(id);
193 // the following constructor also sets the default values
194 block_data = new boxm2_data_base(data, type, read_only);
195 }
196
197 // grab a reference to the map of cached_data_
198 std::map<boxm2_block_id, boxm2_data_base*>& data_map = this->cached_data_map(type);
199
200 // then look for the block you're requesting
201 auto iter = data_map.find(id);
202 if ( iter != data_map.end() )
203 {
204 // congrats you've found the data block in cache, now throw it away
205 delete iter->second;
206 data_map.erase(iter);
207 }
208
209 // now store the block in the cache
210 data_map[id] = block_data;
211 return block_data;
212 }
213
214 //: removes data from this cache (may or may not write to disk first)
remove_data_base(boxm2_block_id id,std::string type)215 void boxm2_lru_cache1::remove_data_base(boxm2_block_id id, std::string type)
216 {
217 // grab a reference to the map of cached_data_
218 std::map<boxm2_block_id, boxm2_data_base*>& data_map =
219 this->cached_data_map(type);
220 // then look for the block you're requesting
221 auto rem = data_map.find(id);
222 if ( rem != data_map.end() )
223 {
224 // found the block,
225 boxm2_data_base* litter = data_map[id];
226
227 if (!litter->read_only_) {
228 // save it
229 std::cout<<"boxm2_lru_cache1::remove_data_base "<<type<<':'<<id<<"; saving to disk"<<std::endl;
230 boxm2_sio_mgr::save_block_data_base(scene_dir_, id, litter, type);
231 }
232 else
233 std::cout<<"boxm2_lru_cache1::remove_data_base "<<type<<':'<<id<<"; not saving to disk"<<std::endl;
234 // now throw it away
235 delete litter;
236 data_map.erase(rem);
237 }
238 }
239
240 //: replaces data in the cache with one here
replace_data_base(boxm2_block_id id,std::string type,boxm2_data_base * replacement)241 void boxm2_lru_cache1::replace_data_base(boxm2_block_id id, std::string type, boxm2_data_base* replacement)
242 {
243 // grab a reference to the map of cached_data_
244 std::map<boxm2_block_id, boxm2_data_base*>& data_map =
245 this->cached_data_map(type);
246
247 // find old data base and copy it's read_only/write status
248 auto rem = data_map.find(id);
249 if ( rem != data_map.end() )
250 {
251 // found the block,
252 boxm2_data_base* litter = data_map[id];
253 replacement->read_only_ = litter->read_only_;
254 #if 0 // don't need to write on a replace data...
255 if (!litter->read_only_) {
256 boxm2_sio_mgr::save_block_data_base(scene_dir_, id, litter, type);
257 }
258 #endif
259 // now throw it away
260 delete litter;
261 data_map.erase(rem);
262 }
263
264 // this->remove_data_base(id, type);
265 // put the new one in there
266 data_map[id] = replacement;
267 }
268
269 //: helper method returns a reference to correct data map (ensures one exists)
cached_data_map(const std::string & prefix)270 std::map<boxm2_block_id, boxm2_data_base*>& boxm2_lru_cache1::cached_data_map(const std::string& prefix)
271 {
272 // if map for this particular data type doesn't exist, initialize it
273 if ( cached_data_.find(prefix) == cached_data_.end() )
274 {
275 std::map<boxm2_block_id, boxm2_data_base*> dmap;
276 cached_data_[prefix] = dmap;
277 }
278
279 // grab a reference to the map of cached_data_ and return it
280 std::map<boxm2_block_id, boxm2_data_base*>& data_map = cached_data_[prefix];
281 return data_map;
282 }
283
284 //: helper method says whether or not block id is valid
is_valid_id(const boxm2_block_id & id)285 bool boxm2_lru_cache1::is_valid_id(const boxm2_block_id& id)
286 {
287 // use scene here to determine if this id is valid
288 return scene_->block_exists(id);
289 }
290
291
292 //: Summarizes this cache's data
to_string()293 std::string boxm2_lru_cache1::to_string()
294 {
295 std::stringstream stream;
296 stream << "boxm2_lru_cache1:: scene dir="<<scene_dir_<<'\n'
297 << " blocks: ";
298 std::map<boxm2_block_id, boxm2_block*>::iterator blk_iter;
299 for (blk_iter = cached_blocks_.begin(); blk_iter != cached_blocks_.end(); ++blk_iter) {
300 boxm2_block_id id = blk_iter->first;
301 stream << '(' << id /* << ',' << blk_iter->second */ << ") ";
302 }
303
304 std::map<std::string, std::map<boxm2_block_id, boxm2_data_base*> >::iterator dat_iter;
305 for (dat_iter = cached_data_.begin(); dat_iter != cached_data_.end(); ++dat_iter)
306 {
307 std::string data_type = dat_iter->first;
308 stream<< "\n data: "<<data_type<<' ';
309 std::map<boxm2_block_id, boxm2_data_base*> dmap = dat_iter->second;
310 std::map<boxm2_block_id, boxm2_data_base*>::iterator it;
311 for (it = dmap.begin(); it != dmap.end(); ++it)
312 {
313 boxm2_block_id id = it->first;
314 stream<< '(' << id /*<< ',' <<it->second */<< ") ";
315 }
316 }
317 return stream.str();
318 }
319
320 //: dumps all data onto disk
write_to_disk()321 void boxm2_lru_cache1::write_to_disk()
322 {
323 // save the data and delete
324 for (auto & iter : cached_data_)
325 {
326 for (auto it = iter.second.begin(); it != iter.second.end(); it++) {
327 boxm2_block_id id = it->first;
328 // if (!it->second->read_only_)
329 boxm2_sio_mgr::save_block_data_base(scene_dir_, it->first, it->second, iter.first);
330 }
331 }
332
333 for (auto & cached_block : cached_blocks_)
334 {
335 boxm2_block_id id = cached_block.first;
336 // if (!iter->second->read_only())
337 boxm2_sio_mgr::save_block(scene_dir_, cached_block.second);
338 }
339 }
340
341 //: shows elements in cache
operator <<(std::ostream & s,boxm2_lru_cache1 & scene)342 std::ostream& operator<<(std::ostream &s, boxm2_lru_cache1& scene)
343 {
344 return s << scene.to_string();
345 }
346