list_manager.cpp

Go to the documentation of this file.
00001 /*****************************************************************************\
00002 *                                                                             *
00003 *  Name   : list_manager                                                      *
00004 *  Author : Chris Koeritz                                                     *
00005 *                                                                             *
00006 *******************************************************************************
00007 * Copyright (c) 2002-$now By Author.  This program is free software; you can  *
00008 * redistribute it and/or modify it under the terms of the GNU General Public  *
00009 * License as published by the Free Software Foundation; either version 2 of   *
00010 * the License or (at your option) any later version.  This is online at:      *
00011 *     http://www.fsf.org/copyleft/gpl.html                                    *
00012 * Please send any updates to: fred@gruntose.com                               *
00013 \*****************************************************************************/
00014 
00015 #include "bundle_list.h"
00016 #include "list_manager.h"
00017 
00018 #include <basis/astring.h>
00019 #include <basis/functions.h>
00020 #include <basis/mutex.h>
00021 #include <structures/string_array.h>
00022 
00023 using namespace basis;
00024 using namespace octopi;
00025 using namespace structures;
00026 using namespace timely;
00027 
00028 namespace synchronic {
00029 
00030 //#define DEBUG_LIST_MANAGER
00031   // uncomment for noisier version.
00032 
00033 #undef GRAB_LOCK
00034 #define GRAB_LOCK \
00035   auto_synchronizer l(*_locking)
00036 
00037 #undef LOG
00038 #define LOG(to_print) \
00039   CLASS_EMERGENCY_LOG(program_wide_logger::get(), to_print)
00040 
00041 list_manager::list_manager(const string_array &list_name, bool backgrounded)
00042 : tentacle(list_name, backgrounded),
00043   _entries(new bundle_list),
00044   _locking(new mutex)
00045 {
00046 }
00047 
00048 list_manager::~list_manager()
00049 {
00050   WHACK(_entries);
00051   WHACK(_locking);
00052 }
00053 
00054 const string_array &list_manager::list_name() const { return group(); }
00055 
00056 int list_manager::entries() const
00057 {
00058   GRAB_LOCK;
00059   return _entries->elements();
00060 }
00061 
00062 void list_manager::reset()
00063 {
00064   GRAB_LOCK;
00065   _entries->zap(0, _entries->elements() - 1);
00066 }
00067 
00068 bool list_manager::is_listed(const string_array &classifier)
00069 {
00070   GRAB_LOCK;
00071   int indy = locked_find(classifier);
00072   return !negative(indy);
00073 }
00074 
00075 bool list_manager::update(const string_array &classifier, int offset)
00076 {
00077   GRAB_LOCK;
00078   int indy = locked_find(classifier);
00079   if (negative(indy)) return false;  // not found.
00080   _entries->borrow(indy)->_updated = time_stamp(offset);
00081   return true;
00082 }
00083 
00084 void list_manager::clean(int older_than)
00085 {
00086   GRAB_LOCK;
00087   for (int i = 0; i < _entries->elements(); i++) {
00088     synchronizable *curr = _entries->borrow(i);
00089     if (curr->_updated < time_stamp(-older_than)) {
00090       // this one is too old to keep around.
00091       _entries->zap(i, i);
00092       i--;  // skip back before deleted item.
00093     }
00094   }
00095 }
00096 
00097 bool list_manager::zap(const string_array &classifier)
00098 {
00099   GRAB_LOCK;
00100   int indy = locked_find(classifier);
00101   if (negative(indy)) return false;  // not found.
00102   _entries->zap(indy, indy);
00103   return true;  // did find and whack it.
00104 }
00105 
00106 int list_manager::locked_find(const string_array &classifier)
00107 {
00108   for (int i = 0; i < _entries->elements(); i++) {
00109     // check that the classifier lengths are equal; otherwise no match.
00110     if (_entries->get(i)->classifier().length() != classifier.length())
00111       continue;
00112     // starting from the end of most significance, we compare the strings.
00113     // we don't want to bother comparing the end that's most likely to be
00114     // the same for items in the list (the front, that is).
00115     bool problems = false;
00116     for (int j = classifier.length() - 1; j >= 0; j--) {
00117       if (_entries->get(i)->classifier()[j] != classifier[j]) {
00118         problems = true;
00119         break;  // get out now since we're hosed.
00120       }
00121     }
00122     if (problems) continue;  // nope, there was a mismatch.
00123     // success; this guy matches.
00124     return i;
00125   }
00126   return common::NOT_FOUND;  // not found.
00127 }
00128 
00129 synchronizable *list_manager::clone_object(const string_array &classifier)
00130 {
00131   GRAB_LOCK;
00132   int indy = locked_find(classifier);
00133   if (negative(indy)) return NIL;
00134   return dynamic_cast<synchronizable *>(_entries->get(indy)->clone());
00135 }
00136 
00137 void list_manager::retrieve(bundle_list &to_fill) const
00138 {
00139   to_fill.reset();
00140   GRAB_LOCK;
00141   for (int i = 0; i < _entries->elements(); i++)
00142     to_fill += dynamic_cast<synchronizable *>(_entries->get(i)->clone());
00143 }
00144 
00145 outcome list_manager::consume(infoton &to_chow,
00146     const octopus_request_id &formal(item_id), byte_array &transformed)
00147 {
00148 #ifdef DEBUG_LIST_MANAGER
00149   FUNCDEF("consume");
00150 #endif
00151   transformed.reset();
00152   synchronizable *bun = dynamic_cast<synchronizable *>(&to_chow);
00153   if (!bun) return BAD_INPUT;
00154 
00155   GRAB_LOCK;
00156 
00157   // now perform an appropriate action depending on the type of update.
00158   switch (bun->_mod) {
00159     case synchronizable::ADDED:
00160     case synchronizable::CHANGED: {
00161       // see if the item already exists; if it does, overwrite it.
00162       int indy = locked_find(bun->classifier());
00163       if (negative(indy)) {
00164         // the item is new, so just drop it in the list.
00165         *_entries += dynamic_cast<synchronizable *>(bun->clone());
00166       } else {
00167         // not a new item, so merge with the existing contents.
00168         _entries->borrow(indy)->merge(*bun);
00169         _entries->borrow(indy)->_updated = time_stamp();
00170       }
00171       return OKAY;
00172     }
00173     case synchronizable::DELETED: {
00174       int indy = locked_find(bun->classifier());
00175       if (non_negative(indy)) {
00176         // found it, so whack the entry as needed by calling merge.
00177         outcome ret = _entries->borrow(indy)->merge(*bun);
00178         _entries->borrow(indy)->_updated = time_stamp();
00179         if (ret == synchronizable::EMPTY) {
00180           // they have told us that this must go now.
00181 #ifdef DEBUG_LIST_MANAGER
00182           LOG(astring("removing entry now due to merge outcome: ")
00183               + _entries->borrow(indy)->text_form());
00184 #endif
00185           _entries->zap(indy, indy);
00186         }
00187         return OKAY;
00188       } else {
00189         // that item was not listed.
00190 #ifdef DEBUG_LIST_MANAGER
00191         LOG(astring("could not find entry for ") + bun->text_form());
00192 #endif
00193         return NOT_FOUND;
00194       }
00195       break;
00196     }
00197     default: return NO_HANDLER;
00198   }
00199   return OKAY;
00200 }
00201 
00202 void list_manager::expunge(const octopus_entity &formal(to_remove))
00203 {
00204 //  FUNCDEF("expunge");
00205 }
00206 
00207 } //namespace.
00208 
Generated on Sat Jan 28 04:22:44 2012 for hoople2 project by  doxygen 1.6.3