1 /*****************************************************************************\
3 * Name : list_manager *
4 * Author : Chris Koeritz *
6 *******************************************************************************
7 * Copyright (c) 2002-$now By Author. This program is free software; you can *
8 * redistribute it and/or modify it under the terms of the GNU General Public *
9 * License as published by the Free Software Foundation; either version 2 of *
10 * the License or (at your option) any later version. This is online at: *
11 * http://www.fsf.org/copyleft/gpl.html *
12 * Please send any updates to: fred@gruntose.com *
13 \*****************************************************************************/
15 #include "bundle_list.h"
16 #include "list_manager.h"
18 #include <basis/astring.h>
19 #include <basis/functions.h>
20 #include <basis/mutex.h>
21 #include <structures/string_array.h>
23 using namespace basis;
24 using namespace octopi;
25 using namespace structures;
26 using namespace timely;
28 namespace synchronic {
30 //#define DEBUG_LIST_MANAGER
31 // uncomment for noisier version.
35 auto_synchronizer l(*_locking)
38 #define LOG(to_print) \
39 CLASS_EMERGENCY_LOG(program_wide_logger::get(), to_print)
41 list_manager::list_manager(const string_array &list_name, bool backgrounded)
42 : tentacle(list_name, backgrounded),
43 _entries(new bundle_list),
48 list_manager::~list_manager()
54 const string_array &list_manager::list_name() const { return group(); }
56 int list_manager::entries() const
59 return _entries->elements();
62 void list_manager::reset()
65 _entries->zap(0, _entries->elements() - 1);
68 bool list_manager::is_listed(const string_array &classifier)
71 int indy = locked_find(classifier);
72 return !negative(indy);
75 bool list_manager::update(const string_array &classifier, int offset)
78 int indy = locked_find(classifier);
79 if (negative(indy)) return false; // not found.
80 _entries->borrow(indy)->_updated = time_stamp(offset);
84 void list_manager::clean(int older_than)
87 for (int i = 0; i < _entries->elements(); i++) {
88 synchronizable *curr = _entries->borrow(i);
89 if (curr->_updated < time_stamp(-older_than)) {
90 // this one is too old to keep around.
92 i--; // skip back before deleted item.
97 bool list_manager::zap(const string_array &classifier)
100 int indy = locked_find(classifier);
101 if (negative(indy)) return false; // not found.
102 _entries->zap(indy, indy);
103 return true; // did find and whack it.
106 int list_manager::locked_find(const string_array &classifier)
108 for (int i = 0; i < _entries->elements(); i++) {
109 // check that the classifier lengths are equal; otherwise no match.
110 if (_entries->get(i)->classifier().length() != classifier.length())
112 // starting from the end of most significance, we compare the strings.
113 // we don't want to bother comparing the end that's most likely to be
114 // the same for items in the list (the front, that is).
115 bool problems = false;
116 for (int j = classifier.length() - 1; j >= 0; j--) {
117 if (_entries->get(i)->classifier()[j] != classifier[j]) {
119 break; // get out now since we're hosed.
122 if (problems) continue; // nope, there was a mismatch.
123 // success; this guy matches.
126 return common::NOT_FOUND; // not found.
129 synchronizable *list_manager::clone_object(const string_array &classifier)
132 int indy = locked_find(classifier);
133 if (negative(indy)) return NIL;
134 return dynamic_cast<synchronizable *>(_entries->get(indy)->clone());
137 void list_manager::retrieve(bundle_list &to_fill) const
141 for (int i = 0; i < _entries->elements(); i++)
142 to_fill += dynamic_cast<synchronizable *>(_entries->get(i)->clone());
145 outcome list_manager::consume(infoton &to_chow,
146 const octopus_request_id &formal(item_id), byte_array &transformed)
148 #ifdef DEBUG_LIST_MANAGER
152 synchronizable *bun = dynamic_cast<synchronizable *>(&to_chow);
153 if (!bun) return BAD_INPUT;
157 // now perform an appropriate action depending on the type of update.
159 case synchronizable::ADDED:
160 case synchronizable::CHANGED: {
161 // see if the item already exists; if it does, overwrite it.
162 int indy = locked_find(bun->classifier());
163 if (negative(indy)) {
164 // the item is new, so just drop it in the list.
165 *_entries += dynamic_cast<synchronizable *>(bun->clone());
167 // not a new item, so merge with the existing contents.
168 _entries->borrow(indy)->merge(*bun);
169 _entries->borrow(indy)->_updated = time_stamp();
173 case synchronizable::DELETED: {
174 int indy = locked_find(bun->classifier());
175 if (non_negative(indy)) {
176 // found it, so whack the entry as needed by calling merge.
177 outcome ret = _entries->borrow(indy)->merge(*bun);
178 _entries->borrow(indy)->_updated = time_stamp();
179 if (ret == synchronizable::EMPTY) {
180 // they have told us that this must go now.
181 #ifdef DEBUG_LIST_MANAGER
182 LOG(astring("removing entry now due to merge outcome: ")
183 + _entries->borrow(indy)->text_form());
185 _entries->zap(indy, indy);
189 // that item was not listed.
190 #ifdef DEBUG_LIST_MANAGER
191 LOG(astring("could not find entry for ") + bun->text_form());
197 default: return NO_HANDLER;
202 void list_manager::expunge(const octopus_entity &formal(to_remove))
204 // FUNCDEF("expunge");