00001 #ifndef OBJECT_CATALOG_IMPLEMENTATION_FILE
00002 #define OBJECT_CATALOG_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #include "catalogable.h"
00019 #include "node.h"
00020 #include "object_catalog.h"
00021 #include "safe_list.h"
00022 #include "safe_node.h"
00023
00024 #include <basis/array.cpp>
00025 #include <basis/log_base.h>
00026 #include <basis/mutex.h>
00027 #include <data_struct/unique_id.h>
00028
00029 #undef LOG
00030 #define LOG(s) CLASS_EMERGENCY_LOG(program_wide_logger(), s)
00031
00032 namespace nodes {
00033
00034 class objcat_internal_safe_list : public safe_list
00035 {
00036 public:
00037 objcat_internal_safe_list() : safe_list() {}
00038 };
00039
00040 class objcat_internal_write_iterator
00041 {
00042 public:
00043 objcat_internal_write_iterator(safe_list_write_iterator *to_hold)
00044 : _writ(to_hold) {}
00045 safe_list_write_iterator *_writ;
00046 };
00047
00049
00050 class objcat_catalogable_node : public safe_node
00051 {
00052 public:
00053 objcat_catalogable_node(catalogable *to_hold)
00054 : safe_node(), _cat(to_hold) {}
00055 ~objcat_catalogable_node() { WHACK(_cat); }
00056
00057 catalogable &cat() { return *_cat; }
00058
00059
00060 void begin_write() { if (_cat) _cat->lock(); }
00061 void end_write() { if (_cat) _cat->unlock(); }
00062
00063 void reset() { _cat = NIL; }
00064
00065
00066
00067 private:
00068 catalogable *_cat;
00069
00070
00071 objcat_catalogable_node(const objcat_catalogable_node &);
00072 objcat_catalogable_node &operator =(const objcat_catalogable_node &);
00073 };
00074
00076
00077
00078 #define UPCAST_CAT \
00079 objcat_catalogable_node *catnode = NIL; \
00080 if (!_iter->_writ->is_tail()) \
00081 catnode = dynamic_cast<objcat_catalogable_node *>(_iter->_writ->access())
00082
00083 #define LOCK_CAT { UPCAST_CAT; if (catnode) catnode->begin_write(); }
00084 #define UNLOCK_CAT { UPCAST_CAT; if (catnode) catnode->end_write(); }
00085
00086 objcat_iterator::objcat_iterator()
00087 : _disabled(false), _iter(NIL) {}
00088
00089 objcat_iterator::~objcat_iterator() { WHACK(_iter); }
00090
00091 catalogable &objcat_locket::cat() { return _held->cat(); }
00092
00093 bool objcat_iterator::is_head() { return _iter->_writ->is_head(); }
00094
00095 bool objcat_iterator::is_tail() { return _iter->_writ->is_tail(); }
00096
00097 void objcat_iterator::next()
00098 { if (_disabled) return; _iter->_writ->next(); }
00099
00100 void objcat_iterator::previous()
00101 { if (_disabled) return; _iter->_writ->previous(); }
00102
00103 void objcat_iterator::jump_head()
00104 { if (_disabled) return; _iter->_writ->jump_head(); }
00105
00106 void objcat_iterator::jump_tail()
00107 { if (_disabled) return; _iter->_writ->jump_tail(); }
00108
00109 const catalogable *objcat_iterator::cat()
00110 {
00111 if (!_iter->_writ->access()) return NIL;
00112 UPCAST_CAT;
00113 return catnode? &catnode->cat() : NIL;
00114 }
00115
00116 objcat_locket *objcat_iterator::open_locket()
00117 {
00118 if (_disabled) return NIL;
00119 UPCAST_CAT;
00120 if (!catnode) return NIL;
00121 _disabled = true;
00122 LOCK_CAT;
00123 objcat_locket *to_return = new objcat_locket(catnode, this);
00124 return to_return;
00125 }
00126
00127 void objcat_iterator::close_locket(objcat_locket * &to_close)
00128 {
00129 if (!to_close) return;
00130 UNLOCK_CAT;
00131 _disabled = false;
00132 WHACK(to_close);
00133 }
00134
00136
00137 objcat_isolater::objcat_isolater(objcat_catalogable_node *to_hold)
00138 : _held(to_hold) {}
00139
00140 objcat_isolater::~objcat_isolater() {}
00141
00142 catalogable &objcat_isolater::cat() { return _held->cat(); }
00143
00145
00146
00147 class defunct_nodes_pokey : public array<objcat_catalogable_node *>
00148 {
00149 };
00150
00152
00153 object_catalog::object_catalog()
00154 : _base(new objcat_internal_safe_list),
00155 _defunct(new defunct_nodes_pokey),
00156 _pokey_protector(new mutex)
00157 {}
00158
00159 object_catalog::~object_catalog()
00160 {
00161 clear_pokey();
00162 WHACK(_base);
00163 WHACK(_defunct);
00164 WHACK(_pokey_protector);
00165 }
00166
00167 void object_catalog::clear_pokey()
00168 {
00169 FUNCDEF("clear_pokey");
00170 auto_synchronizer l(*_pokey_protector);
00171
00172 while (_defunct->length()) {
00173 objcat_catalogable_node *gone = _defunct->get(0);
00174 if (!gone)
00175 non_continuable_error(static_class_name(), func, "bad entry in defunct list");
00176 _defunct->zap(0, 0);
00177 gone->begin_write();
00178
00179
00180 gone->end_write();
00181 WHACK(gone);
00182 }
00183 }
00184
00185 outcome object_catalog::zap(objcat_iterator &where)
00186 {
00187 if (where._disabled) return BAD_ITERATOR;
00188 safe_node *node_0 = _base->remove(*where._iter->_writ);
00189 if (!node_0) return BAD_ITERATOR;
00190
00191 objcat_catalogable_node *the_node
00192 = dynamic_cast<objcat_catalogable_node *>(node_0);
00193 auto_synchronizer l(*_pokey_protector);
00194 *_defunct += the_node;
00195 return OKAY;
00196 }
00197
00198 outcome object_catalog::insert(objcat_iterator &where,
00199 catalogable *to_add)
00200 {
00201 if (where._disabled) return BAD_ITERATOR;
00202 if (!where._iter || !where._iter->_writ) return BAD_ITERATOR;
00203 objcat_catalogable_node *new_node = new objcat_catalogable_node(to_add);
00204
00205 _base->insert(*where._iter->_writ, new_node);
00206 return OKAY;
00207 }
00208
00209 bool object_catalog::empty(objcat_iterator &where)
00210 { return _base->empty(*where._iter->_writ); }
00211
00212 catalogable *object_catalog::acquire(const unique_int &to_find)
00213 {
00214 clear_pokey();
00215 objcat_internal_write_iterator iter(_base->open_writer());
00216
00217
00218 for ( ; !iter._writ->is_tail(); iter._writ->next()) {
00219
00220 objcat_catalogable_node *cat = dynamic_cast<objcat_catalogable_node *>
00221 (iter._writ->access());
00222 if (!cat) continue;
00223 if (cat->cat().id() == to_find) {
00224
00225 safe_node *node_0 = _base->remove(*iter._writ);
00226 objcat_catalogable_node *bye
00227 = dynamic_cast<objcat_catalogable_node *>(node_0);
00228
00229 _base->close_writer(iter._writ);
00230
00231
00232 catalogable *to_return = &bye->cat();
00233
00234
00235
00236 bye->begin_write();
00237
00238
00239
00240
00241 bye->end_write();
00242
00243
00244
00245
00246
00247
00248 bye->reset();
00249 WHACK(bye);
00250 return to_return;
00251 }
00252 }
00253 _base->close_writer(iter._writ);
00254 return NIL;
00255 }
00256
00257 int object_catalog::elements(objcat_iterator &finder)
00258 { return _base->elements(*finder._iter->_writ); }
00259
00260 outcome object_catalog::add(catalogable *to_add)
00261 {
00262 clear_pokey();
00263 objcat_iterator *finding = find(to_add->id());
00264 if (finding) {
00265 iter_unlock(finding);
00266 delete to_add;
00267 return IN_USE;
00268 }
00269 objcat_internal_write_iterator iter(_base->open_writer(safe_list::TAIL));
00270 objcat_catalogable_node *new_node = new objcat_catalogable_node(to_add);
00271 _base->insert(*iter._writ, new_node);
00272 _base->close_writer(iter._writ);
00273 return OKAY;
00274 }
00275
00276 objcat_iterator *object_catalog::find_head()
00277 {
00278 clear_pokey();
00279 objcat_iterator *to_return = new objcat_iterator;
00280 to_return->_iter = new objcat_internal_write_iterator(_base->open_writer());
00281 return to_return;
00282 }
00283
00284 objcat_iterator *object_catalog::find_tail()
00285 {
00286 clear_pokey();
00287 objcat_iterator *to_return = new objcat_iterator;
00288 to_return->_iter = new objcat_internal_write_iterator
00289 (_base->open_writer(safe_list::TAIL));
00290 return to_return;
00291 }
00292
00293 objcat_iterator *object_catalog::find(const unique_int &id)
00294 {
00295 clear_pokey();
00296 objcat_iterator *to_return = new objcat_iterator;
00297 to_return->_iter = new objcat_internal_write_iterator(_base->open_writer());
00298 for ( ; !to_return->_iter->_writ->is_tail();
00299 to_return->_iter->_writ->next()) {
00300 objcat_catalogable_node *cat = dynamic_cast<objcat_catalogable_node *>
00301 (to_return->_iter->_writ->access());
00302 if (cat && (cat->cat().id() == id)) {
00303 return to_return;
00304 }
00305 }
00306 _base->close_writer(to_return->_iter->_writ);
00307 delete to_return;
00308 return NIL;
00309 }
00310
00311 void object_catalog::iter_unlock(objcat_iterator * &to_unlock)
00312 {
00313 if (!to_unlock) return;
00314
00315
00316 _base->close_writer(to_unlock->_iter->_writ);
00317 WHACK(to_unlock);
00318 }
00319
00320 outcome object_catalog::zap_id(const unique_int &id)
00321 {
00322 clear_pokey();
00323 catalogable *found = acquire(id);
00324 if (!found) return NOT_FOUND;
00325 WHACK(found);
00326 return OKAY;
00327 }
00328
00329 void object_catalog::apply(apply_function *to_apply, void *data_link)
00330 {
00331 clear_pokey();
00332 objcat_internal_write_iterator iter(_base->open_writer());
00333 for ( ; !iter._writ->is_tail(); iter._writ->next()) {
00334 objcat_catalogable_node *cat = dynamic_cast<objcat_catalogable_node *>
00335 (iter._writ->access());
00336 if (cat) {
00337 cat->begin_write();
00338 bool ret = to_apply(cat->cat(), data_link);
00339 cat->end_write();
00340 if (!ret) {
00341 _base->close_writer(iter._writ);
00342 return;
00343 }
00344 }
00345 }
00346 _base->close_writer(iter._writ);
00347 }
00348
00349 objcat_isolater *object_catalog::separate(objcat_iterator * &to_separate)
00350 {
00351 if (!to_separate || !to_separate->_iter->_writ->access()) return NIL;
00352 if (to_separate->_disabled) return NIL;
00353 objcat_catalogable_node *cat = dynamic_cast<objcat_catalogable_node *>
00354 (to_separate->_iter->_writ->access());
00355 cat->begin_write();
00356 objcat_isolater *to_return = new objcat_isolater(cat);
00357 iter_unlock(to_separate);
00358 return to_return;
00359 }
00360
00361 void object_catalog::rejoin(objcat_isolater * &to_unlock)
00362 {
00363 if (!to_unlock) return;
00364 to_unlock->_held->end_write();
00365 WHACK(to_unlock);
00366 }
00367
00368 }
00369
00370
00371 #endif //OBJECT_CATALOG_IMPLEMENTATION_FILE
00372