list_manager.cpp

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

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