object_catalog.cpp

Go to the documentation of this file.
00001 #ifndef OBJECT_CATALOG_IMPLEMENTATION_FILE
00002 #define OBJECT_CATALOG_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : object_catalog                                                    *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 1997-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
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     // lets us get at the held catalogable object.
00059 
00060   void begin_write() { if (_cat) _cat->lock(); }
00061   void end_write() { if (_cat) _cat->unlock(); }
00062 
00063   void reset() { _cat = NIL; }
00064     // allows the internally held catalogable to be cleared so it's not
00065     // deleted.  better not call the catalogable conversion after this though.
00066 
00067 private:
00068   catalogable *_cat;
00069 
00070   // forbidden.
00071   objcat_catalogable_node(const objcat_catalogable_node &);
00072   objcat_catalogable_node &operator =(const objcat_catalogable_node &);
00073 };
00074 
00076 
00077 // we can't move the list off the tail if it's already gotten there.
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 // hangs onto nodes that are tossed but which we must postpone deleting.
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     // ensure that only one thread cleans this list at a time.
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();  // ensure we have access to this.
00178     // we know that no one else can get this lock now; the node is already
00179     // not in our main list, so this is safe.
00180     gone->end_write();  // release access.
00181     WHACK(gone);
00182   }
00183 }
00184 
00185 outcome object_catalog::zap(objcat_iterator &where)
00186 {
00187   if (where._disabled) return BAD_ITERATOR;  // can't play with it right now.
00188   safe_node *node_0 = _base->remove(*where._iter->_writ);
00189   if (!node_0) return BAD_ITERATOR;
00190   // move the node to the deleted node list.
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 //hmmm: make the safe list insert return a usable outcome.
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     // we lock the safe list here and don't release it until we're
00217     // sure we've got the item we want.
00218   for ( ; !iter._writ->is_tail(); iter._writ->next()) {
00219     // loop through the list to find our item to remove from the list.
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       // get that list entry.
00225       safe_node *node_0 = _base->remove(*iter._writ);
00226       objcat_catalogable_node *bye
00227           = dynamic_cast<objcat_catalogable_node *>(node_0);
00228       // now release the lock on the whole list.
00229       _base->close_writer(iter._writ);
00230 
00231       // pull the catalogable out of the cat_node.
00232       catalogable *to_return = &bye->cat();
00233 
00234       // lock the node now.  we need to know that no one else is messing
00235       // with it for the moment.
00236       bye->begin_write();
00237 
00238       // remove the lock; it's out of the list already so we don't care about
00239       // future lockers.  they can't get at it any more since it's not in the
00240       // list now.
00241       bye->end_write();
00242 
00243       // at this point, we've safely gotten the item out of the list.  anyone
00244       // who had separated the item will have had to release the list lock
00245       // after they separated.  they might still have had the item locked up
00246       // to the point where our write succeeded on the object.  but after that,
00247       // they've not got the item lock anymore.
00248       bye->reset();  // clear the pointer so the catalogable isn't whacked.
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 //if disabled, we need to shriek about it.  perhaps a logging event?
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 } // namespace.
00369 
00370 
00371 #endif //OBJECT_CATALOG_IMPLEMENTATION_FILE
00372 

Generated on Fri Nov 28 04:29:17 2008 for HOOPLE Libraries by  doxygen 1.5.1