servlib/prophet/AckList.cc
changeset 0 2b3e5ec03512
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/servlib/prophet/AckList.cc	Thu Apr 21 14:57:45 2011 +0100
@@ -0,0 +1,170 @@
+/*
+ *    Copyright 2007 Baylor University
+ *
+ *    Licensed under the Apache License, Version 2.0 (the "License");
+ *    you may not use this file except in compliance with the License.
+ *    You may obtain a copy of the License at
+ *
+ *        http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *    Unless required by applicable law or agreed to in writing, software
+ *    distributed under the License is distributed on an "AS IS" BASIS,
+ *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *    See the License for the specific language governing permissions and
+ *    limitations under the License.
+ */
+
+#include <time.h>
+#include "BundleCore.h"
+#include "AckList.h"
+
+namespace prophet
+{
+
+AckList::~AckList()
+{
+    for (palist::iterator i = acks_.begin(); i != acks_.end(); i++)
+    {
+        delete (*i);
+    }
+    acks_.clear();
+}
+
+bool
+AckList::insert(const std::string& dest_id, u_int32_t cts,
+                u_int32_t seq, u_int32_t ets)
+{
+    // default to 1 day
+    if (ets == 0) ets = 86400;
+
+    Ack a(dest_id,cts,seq,ets); 
+    return insert(&a);
+}
+
+bool
+AckList::insert(const Bundle* b, const BundleCore* core)
+{
+    if (b == NULL || core == NULL) return false;
+
+    return insert(core->get_route(b->destination_id()),
+                  b->creation_ts(),
+                  b->sequence_num(),
+                  b->expiration_ts());
+}
+
+bool
+AckList::insert(const Ack* a)
+{
+    if (a == NULL) return false;
+
+    Ack* na = new Ack(*a);
+
+    // attempt to insert
+    if (acks_.insert(na).second)
+        return true;
+
+    // failed, so free up memory
+    delete na;
+    return false;
+}
+
+size_t
+AckList::clone(PointerList<Ack>& list) const
+{
+    size_t num = 0;
+    // clear the incoming
+    list.clear();
+    // walk the internal, visiting each Ack
+    for (palist::const_iterator i = acks_.begin(); i != acks_.end(); i++)
+    {
+        // give away a copy of each visited Ack
+        list.push_back(new Ack(**i));
+        // ... counting as we go
+        num++;
+    }
+    // inform caller of how many elements
+    return num;
+}
+
+size_t
+AckList::fetch(const std::string& dest_id, PointerList<Ack>* list) const
+{
+    size_t num = 0;
+
+    // clear incoming, if set
+    if (list != NULL) list->clear();
+
+    // create a search parameter of palist::key_type
+    Ack a(dest_id);
+
+    // find the beginning of the sequence that matches dest_id
+    palist::const_iterator i = acks_.lower_bound(&a);
+
+    // walk along until either the string no longer matches or
+    // we fall off the end of the sequence
+    while (i != acks_.end() && (*i)->dest_id().compare(dest_id) == 0)
+    {
+        // if set, give the list pointer a copy of each Ack we find
+        if (list != NULL) list->push_back(new Ack(**(i++)));
+        num++;
+    }
+
+    // inform the caller of how many were found
+    return num;
+}
+
+size_t
+AckList::expire()
+{
+    size_t num = 0;
+
+    // grab current epoch seconds
+    time_t now = time(0);
+
+    // walk the list of Acks, careful how we increment since
+    // the erase() operation screws up iterator state
+    for (palist::iterator i = acks_.begin(); i != acks_.end(); )
+    {
+        Ack* a = *i;
+        // test for expired condition
+        if (now - a->cts() > a->ets())
+        {
+            num++;
+            // post increment to sidestep iterator screwiness
+            acks_.erase(i++);
+            // clear up memory 
+            delete a;
+        }
+        // not expired, increment past this one
+        else i++;
+    }
+    // inform caller of how many were removed
+    return num;
+}
+
+bool
+AckList::is_ackd(const std::string& dest_id,
+                 u_int32_t cts, u_int32_t seq) const
+{
+    // create search parameter of type palist::key_type
+    Ack a(dest_id);
+
+    // initialize iterator to beginning of matching sequence
+    palist::iterator i = acks_.lower_bound(&a);
+
+    // walk the sequence until no more matches, or end of sequence
+    while (i != acks_.end())
+    {
+        // test for no-more-matches
+        if ((*i)->dest_id().compare(dest_id) != 0)
+            break;
+        // all parameters match?
+        if ((*i)->cts() == cts && (*i)->seq() == seq)
+            return true;
+        i++;
+    }
+    // not found, therefore must not be Ack'd
+    return false;
+}
+
+}; // namespace prophet