Skip to content

Commit

Permalink
SW-8686 Support Capacity One Native Buffers (#110)
Browse files Browse the repository at this point in the history
* Distinguish one and zero capacity native buffers
  • Loading branch information
dskyle committed Oct 3, 2018
1 parent 37e92d2 commit 35cf30d
Show file tree
Hide file tree
Showing 7 changed files with 126 additions and 41 deletions.
40 changes: 23 additions & 17 deletions include/madara/knowledge/KnowledgeRecord.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,8 @@
#include "madara/utility/IntTypes.h"
#include "madara/utility/SupportTest.h"
#include "madara/utility/CircularBuffer.h"
#include "Any.h"
#include "madara/exceptions/IndexException.h"
#include "madara/knowledge/Any.h"

namespace madara
{
Expand Down Expand Up @@ -1640,7 +1641,7 @@ class MADARA_EXPORT KnowledgeRecord
}
else
{
return 1;
return 0;
}
}

Expand All @@ -1649,12 +1650,16 @@ class MADARA_EXPORT KnowledgeRecord
* modification to this record will write a new entry in this history.
* Once the capacity is met, the oldest entry will be discarded as new
* entries are added.
*
* Note that this capacity includes current value of the record. A capacity
* of zero indicates that this record holds no buffer, whereas one indicates
* that this record has a buffer of size 1.
**/
void set_history_capacity(size_t size)
{
if (type_ == BUFFER)
{
if (size <= 1)
if (size == 0)
{
if (!buf_->empty())
{
Expand All @@ -1670,19 +1675,16 @@ class MADARA_EXPORT KnowledgeRecord
buf_->reserve(size);
}
}
else
else if (size > 0)
{
if (size > 1)
{
KnowledgeRecord tmp = *this;
KnowledgeRecord tmp = *this;

new (&buf_) std::shared_ptr<CircBuf>(std::make_shared<CircBuf>(size));
type_ = BUFFER;
new (&buf_) std::shared_ptr<CircBuf>(std::make_shared<CircBuf>(size));
type_ = BUFFER;

if (tmp.exists())
{
buf_->push_back(std::move(tmp));
}
if (tmp.exists())
{
buf_->push_back(std::move(tmp));
}
}
}
Expand Down Expand Up @@ -1994,26 +1996,30 @@ class MADARA_EXPORT KnowledgeRecord

/**
* Gets the absolute index of the newest element in stored history.
* If this record doesn't have history capacity, returns 0.
* If this record doesn't have history capacity, throws IndexException
**/
size_t get_history_newest_index() const
{
if (!has_history())
{
return 0;
throw exceptions::IndexException(
"KnowledgeRecord::get_history_newest_index: "
"record has zero capacity");
}
return buf_->back_index();
}

/**
* Gets the absolute index of the oldest element in stored history.
* If this record doesn't have history capacity, returns 0.
* If this record doesn't have history capacity, throws IndexException
**/
size_t get_history_oldest_index() const
{
if (!has_history())
{
return 0;
throw exceptions::IndexException(
"KnowledgeRecord::get_history_oldest_index: "
"record has zero capacity");
}
return buf_->front_index();
}
Expand Down
12 changes: 11 additions & 1 deletion include/madara/knowledge/ThreadSafeContext.inl
Original file line number Diff line number Diff line change
Expand Up @@ -952,6 +952,12 @@ inline void ThreadSafeContext::mark_modified(
const VariableReference& ref, const KnowledgeUpdateSettings& settings)
{
MADARA_GUARD_TYPE guard(mutex_);

auto record = ref.get_record_unsafe();

record->clock = clock_;
record->set_toi(utility::get_time());

mark_and_signal(ref, settings);
}

Expand Down Expand Up @@ -1082,9 +1088,13 @@ inline void ThreadSafeContext::apply_modified(void)
// i->second.status = KnowledgeRecord::MODIFIED;

if (entry.second.status() != knowledge::KnowledgeRecord::UNCREATED)
mark_and_signal(&entry, KnowledgeUpdateSettings());
{
mark_modified(&entry, KnowledgeUpdateSettings());
}
else
{
entry.second.set_value(KnowledgeRecord::Integer(0));
}

// i->second.clock = this->clock_;
}
Expand Down
24 changes: 24 additions & 0 deletions include/madara/knowledge/containers/NativeCircularBufferConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,9 @@ namespace containers
* This class provides a subset of the capabilities of CircularBufferConsumer,
* as KnowledgeRecord itself provides equivalents of the rest. Use get_record()
* to access the KnowledgeRecord backing a NativeCircularBufferConsumer.
*
* This class should only be used with records which have history capacity of
* at least 1. Most methods will throw IndexException if not.
*/
class MADARA_EXPORT NativeCircularBufferConsumer
{
Expand Down Expand Up @@ -122,6 +125,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* Consumes the record at the local index (not the producer index)
* @return the last added record. exists() will return false if the
* record is invalid
* @throw exceptions::IndexException if target has no history capacity set
**/
inline madara::knowledge::KnowledgeRecord consume(void) const;

Expand All @@ -133,6 +137,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* occur when the producer produces faster than the
* consumer can consume. This value is essentially
* index_ - local_index - size ().
* @throw exceptions::IndexException if target has no history capacity set
**/
KnowledgeRecord consume(size_t& dropped) const;

Expand All @@ -143,6 +148,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* occur when the producer produces faster than the
* consumer can consume. This value is essentially
* index_ - local_index - size ().
* @throw exceptions::IndexException if target has no history capacity set
**/
template<typename T>
void consume(T& value, size_t& dropped) const;
Expand All @@ -152,6 +158,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* index (not the producer index).
* @param count the maximum number of records to return
* @param values the latest records
* @throw exceptions::IndexException if target has no history capacity set
**/
template<typename T>
void peek_latest(size_t count, std::vector<T>& values) const;
Expand All @@ -161,13 +168,15 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* index (not the producer index).
* @param count the maximum number of records to return
* @return the latest peeked (not consumed) count elements
* @throw exceptions::IndexException if target has no history capacity set
**/
inline std::vector<KnowledgeRecord> peek_latest(size_t count) const;

/**
* Peeks, but does not consume, the latest the record at the local
* index (not the producer index).
* @return the latest element
* @throw exceptions::IndexException if target has no history capacity set
**/
inline madara::knowledge::KnowledgeRecord peek_latest(void) const;

Expand All @@ -176,13 +185,15 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* (not the producer index).
* @param count the maximum number of records to return
* @return the latest count consumed elements
* @throw exceptions::IndexException if target has no history capacity set
**/
inline std::vector<KnowledgeRecord> consume_latest(size_t count) const;

/**
* Consumes the latest the record at the local index
* (not the producer index).
* @return the latest element (singular)
* @throw exceptions::IndexException if target has no history capacity set
**/
inline madara::knowledge::KnowledgeRecord consume_latest(void) const;

Expand All @@ -192,6 +203,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* @param count the maximum number of records to return
* @param dropped the number of dropped records
* @return the latest count elements and number of elements dropped.
* @throw exceptions::IndexException if target has no history capacity set
**/
std::vector<KnowledgeRecord> consume_latest(
size_t count, size_t& dropped) const;
Expand All @@ -201,6 +213,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* (not the producer index).
* @param count the maximum number of records to return
* @param values the latest records
* @throw exceptions::IndexException if target has no history capacity set
**/
template<typename T>
void consume_latest(size_t count, std::vector<T>& values) const;
Expand All @@ -211,6 +224,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* @param count the maximum number of records to return
* @param values the latest records
* @param dropped the number of dropped records
* @throw exceptions::IndexException if target has no history capacity set
**/
template<typename T>
void consume_latest(
Expand All @@ -219,6 +233,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
/**
* Returns the number of known drops since last consume
* @return the number of drops
* @throw exceptions::IndexException if target has no history capacity set
**/
size_t get_dropped(void) const;

Expand All @@ -228,6 +243,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* @return the number of records remaining for consume
* @throw exceptions::ContextException if name or context haven't
* been set appropriately
* @throw exceptions::IndexException if target has no history capacity set
**/
size_t remaining(void) const;

Expand All @@ -236,6 +252,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* @return the number of records in the NativeCircularBufferConsumer
* @throw exceptions::ContextException if name or context haven't
* been set appropriately
* @throw exceptions::IndexException if target has no history capacity set
**/
size_t count(void) const;

Expand Down Expand Up @@ -272,6 +289,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* Consumes (earliest) records from the local index
* @param count the maximum number of records to return
* @param values the last added records
* @throw exceptions::IndexException if target has no history capacity set
**/
template<typename T>
void consume_many(size_t count, std::vector<T>& values) const;
Expand All @@ -282,6 +300,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* @return the last added records
* @throw exceptions::ContextException if name or context have not
* been set appropriately
* @throw exceptions::IndexException if target has no history capacity set
**/
std::vector<KnowledgeRecord> consume_many(size_t count) const;

Expand All @@ -294,6 +313,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* @return the last added records
* @throw exceptions::ContextException if name or context have not
* been set appropriately
* @throw exceptions::IndexException if target has no history capacity set
**/
std::vector<KnowledgeRecord> consume_many(
size_t count, size_t& dropped) const;
Expand All @@ -306,6 +326,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* NativeCircularBufferConsumer
* @throw exceptions::ContextException if name or context haven't
* been set appropriately
* @throw exceptions::IndexException if target has no history capacity set
**/
template<typename T>
void inspect(KnowledgeRecord::Integer position, T& value) const;
Expand All @@ -318,6 +339,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* @return the values at the position in the NativeCircularBufferConsumer
* @throw exceptions::ContextException if name or context haven't
* been set appropriately
* @throw exceptions::IndexException if target has no history capacity set
**/
std::vector<KnowledgeRecord> inspect(
KnowledgeRecord::Integer position, size_t count) const;
Expand All @@ -331,6 +353,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* NativeCircularBufferConsumer
* @throw exceptions::ContextException if name or context haven't
* been set appropriately
* @throw exceptions::IndexException if target has no history capacity set
**/
template<typename T>
void inspect(KnowledgeRecord::Integer position, size_t count,
Expand All @@ -345,6 +368,7 @@ class MADARA_EXPORT NativeCircularBufferConsumer
* been set appropriately
* @throw exceptions::ContextException if name or context haven't
* been set appropriately
* @throw exceptions::IndexException if target has no history capacity set
**/
madara::knowledge::KnowledgeRecord inspect(
KnowledgeRecord::Integer position) const;
Expand Down
6 changes: 6 additions & 0 deletions include/madara/utility/CircularBuffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,12 @@ class CircularBuffer
**/
void reserve(size_t size)
{
if (size == cap_)
{
// Nothing to do
return;
}

CircularBuffer tmp(size, front_);
while (!empty())
{
Expand Down
29 changes: 29 additions & 0 deletions tests/test.h
Original file line number Diff line number Diff line change
Expand Up @@ -63,4 +63,33 @@ static inline void madara_tests_reset_count()
#define TEST_GT(lhs, rhs) TEST_OP(lhs, >, rhs)
#define TEST_GE(lhs, rhs) TEST_OP(lhs, >=, rhs)

#define EXPECT_EXCEPTION(EXCEPTION__, ...) \
do \
{ \
try \
{ \
do \
{ \
__VA_ARGS__ \
} while (0); \
log("FAIL : no exception thrown; expected " #EXCEPTION__ "\n"); \
++madara_tests_fail_count; \
} \
catch (EXCEPTION__ e) \
{ \
log("SUCCESS : caught exception " #EXCEPTION__ ": %s\n", e.what()); \
} \
catch (std::exception e) \
{ \
log("FAIL : expected thrown " #EXCEPTION__ ", got: %s\n", e.what()); \
++madara_tests_fail_count; \
} \
catch (...) \
{ \
log("FAIL : expected thrown " #EXCEPTION__ \
", got unknown excpetion\n"); \
++madara_tests_fail_count; \
} \
} while (0)

#endif
22 changes: 22 additions & 0 deletions tests/test_circular_buffer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -304,6 +304,28 @@ void test_container()

kb.set(key, 123);
TEST_EQ(buf2.consume(), 123);

key = "nobuf";
NativeCircularBufferConsumer buf3(key, kb);

EXPECT_EXCEPTION(exceptions::IndexException, buf3.consume(););
EXPECT_EXCEPTION(exceptions::IndexException, buf3.consume_many(10););

kb.set_history_capacity(key, 0);

EXPECT_EXCEPTION(exceptions::IndexException, buf3.consume(););
EXPECT_EXCEPTION(exceptions::IndexException, buf3.consume_many(10););

key = "buf1";
NativeCircularBufferConsumer buf4(key, kb);
kb.set_history_capacity(key, 1);

TEST_EQ(buf4.consume().exists(), false);

kb.set(key, 12);

TEST_EQ(buf4.consume(), 12);
TEST_EQ(buf4.consume().exists(), false);
}

int main(int, char**)
Expand Down

0 comments on commit 35cf30d

Please sign in to comment.