1 /**
2  *  \file RMF/Category.h
3  *  \brief Handle read/write of Model data from/to files.
4  *
5  *  Copyright 2007-2021 IMP Inventors. All rights reserved.
6  *
7  */
8 
9 #include <algorithm>
10 #include <exception>
11 #include <functional>
12 #include <iostream>
13 #include <string>
14 
15 #include "RMF/ID.h"
16 #include "RMF/compiler_macros.h"
17 #include "RMF/constants.h"
18 #include "RMF/enums.h"
19 #include "RMF/exceptions.h"
20 #include "RMF/infrastructure_macros.h"
21 #include "RMF/internal/SharedData.h"
22 #include "RMF/internal/large_set_map.h"
23 #include "RMF/log.h"
24 #include "RMF/types.h"
25 #include "backend/IO.h"
26 
27 RMF_ENABLE_WARNINGS
28 
29 namespace RMF {
30 namespace internal {
31 
32 namespace {
33 RMF_LARGE_UNORDERED_SET<std::string> open_for_writing;
34 }
SharedData(boost::shared_ptr<backends::IO> io,std::string name,bool write,bool created)35 SharedData::SharedData(boost::shared_ptr<backends::IO> io, std::string name,
36                        bool write, bool created)
37     : path_(name), write_(write), io_(io) {
38   if (!created) {
39     reload();
40   }
41   RMF_USAGE_CHECK(
42       open_for_writing.find(get_file_path()) == open_for_writing.end(),
43       "Opening a file that is still being written is asking for trouble.");
44   if (write) open_for_writing.insert(get_file_path());
45 }
46 
set_loaded_frame(FrameID frame)47 void SharedData::set_loaded_frame(FrameID frame) {
48   RMF_USAGE_CHECK(!write_, "Can't call set loaded frame when writing.");
49   RMF_USAGE_CHECK(frame != ALL_FRAMES, "Trying to set loaded to all frames");
50   RMF_USAGE_CHECK(
51       frame == FrameID() || frame.get_index() < get_number_of_frames(),
52       "Trying to load a frame that isn't there");
53   if (frame == get_loaded_frame()) return;
54   RMF_INFO("Setting loaded frame to " << frame);
55   loaded_frame_ = frame;
56 
57   clear_loaded_values();
58   if (frame != FrameID()) {
59     io_->load_loaded_frame(this);
60   }
61 }
62 
add_frame(std::string name,FrameType type)63 FrameID SharedData::add_frame(std::string name, FrameType type) {
64   RMF_INTERNAL_CHECK(write_, "Can't add frame if not writing");
65   FrameID ret(get_number_of_frames());
66   FrameID cl = get_loaded_frame();
67   RMF_INTERNAL_CHECK(cl != ret, "Huh, frames are the same");
68   if (cl != FrameID()) {
69     if (SharedDataFile::get_is_dirty()) {
70       RMF_INFO("Flushing file info");
71       io_->save_file(this);
72       SharedDataFile::set_is_dirty(false);
73     }
74     if (SharedDataHierarchy::get_is_dirty()) {
75       RMF_INFO("Flushing node hierarchy");
76       io_->save_hierarchy(this);
77       SharedDataHierarchy::set_is_dirty(false);
78     }
79     io_->save_loaded_frame(this);
80   }
81   add_frame_data(ret, name, type);
82 
83   clear_loaded_values();
84   loaded_frame_ = ret;
85   return ret;
86 }
87 
add_frame(std::string name,FrameID parent,FrameType type)88 FrameID SharedData::add_frame(std::string name, FrameID parent,
89                               FrameType type) {
90   FrameID ret = add_frame(name, type);
91   add_child_frame(parent, ret);
92   return ret;
93 }
94 
flush()95 void SharedData::flush() {
96   if (!write_) return;
97   RMF_INFO("Flushing file " << get_file_path());
98   if (SharedDataFile::get_is_dirty()) {
99     RMF_INFO("Flushing file info");
100     io_->save_file(this);
101     SharedDataFile::set_is_dirty(false);
102   }
103   if (SharedDataHierarchy::get_is_dirty()) {
104     RMF_INFO("Flushing node hierarchy");
105     io_->save_hierarchy(this);
106     SharedDataHierarchy::set_is_dirty(false);
107   }
108   if (get_static_is_dirty()) {
109     RMF_INFO("Saving static frame");
110     io_->save_static_frame(this);
111     set_static_is_dirty(false);
112   }
113   io_->flush();
114 }
115 
reload()116 void SharedData::reload() {
117   RMF_INFO("(Re)loading file " << get_file_path());
118   SharedDataHierarchy::clear();
119   io_->load_file(this);
120   SharedDataFile::set_is_dirty(false);
121   io_->load_hierarchy(this);
122   SharedDataHierarchy::set_is_dirty(false);
123 
124   clear_static_values();
125   io_->load_static_frame(this);
126   set_static_is_dirty(false);
127 
128   clear_loaded_values();
129   if (get_loaded_frame() != FrameID() &&
130       get_loaded_frame().get_index() < get_number_of_frames()) {
131     io_->load_loaded_frame(this);
132   }
133 }
134 
~SharedData()135 SharedData::~SharedData() {
136   if (write_) {
137     try {
138       RMF_INFO("Closing file " << get_file_path());
139       flush();
140       if (get_loaded_frame() != FrameID()) {
141         io_->save_loaded_frame(this);
142       }
143       io_.reset();
144     }
145     catch (const std::exception &e) {
146       std::cerr << "Exception caught in shared data destructor " << e.what()
147                 << std::endl;
148     }
149     open_for_writing.erase(get_file_path());
150   }
151 }
152 
153 }  // namespace internal
154 } /* namespace RMF */
155 
156 RMF_DISABLE_WARNINGS
157