-
Notifications
You must be signed in to change notification settings - Fork 275
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Refine publish notifications #271
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,4 +43,22 @@ void ConsumerTableBase::pop(std::string &key, std::string &op, std::vector<Field | |
m_buffer.pop_front(); | ||
} | ||
|
||
bool ConsumerTableBase::hasData() | ||
{ | ||
return RedisSelect::hasData() || !m_buffer.empty(); | ||
} | ||
|
||
// hasCachedData is depreciated, and this is a safe placeholder | ||
// We will use hasData() to indicate that there is pending data | ||
// ref: Select::selecat() implementation | ||
bool ConsumerTableBase::hasCachedData() | ||
{ | ||
return true; | ||
} | ||
|
||
// Override with an empty body, and subclasses will explicitly discard messages in the channel | ||
void ConsumerTableBase::updateAfterRead() | ||
{ | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand why do we need this? |
||
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -27,7 +27,13 @@ void RedisSelect::readData() | |
freeReplyObject(reply); | ||
m_queueLength++; | ||
|
||
reply = nullptr; | ||
readRemainingData(); | ||
} | ||
|
||
/* Read remaining messages in Redis buffer nonblockingly */ | ||
void RedisSelect::readRemainingData() | ||
{ | ||
redisReply *reply = nullptr; | ||
int status; | ||
do | ||
{ | ||
|
@@ -66,6 +72,33 @@ void RedisSelect::updateAfterRead() | |
m_queueLength--; | ||
} | ||
|
||
/* Discard messages in the channel */ | ||
void RedisSelect::discard(long long int n) | ||
{ | ||
readRemainingData(); | ||
|
||
/* | ||
* We will discard at least one message, to prevent any mistakenly infinite loop | ||
* in the select-pop(s) pattern | ||
*/ | ||
if (n <= 0) | ||
n = 1; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In what scenario n <= 0? #Resolved There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I am trying to prevent any logic error outside the scope of RedisSelect. Considering the case if there are redundant notifications but there is no data popped, caller may call discard(0), and here the function consumes one message in the queue if there is any. discard(negative) is not for protection purpose and should be not in a true case. In reply to: 276515380 [](ancestors = 276515380) |
||
|
||
if (n > m_queueLength) | ||
{ | ||
/* If we have less messages, discard them all | ||
* This is no big harm since all the late messages will be selected and nothing popped | ||
* when the channel is not completely busy. | ||
*/ | ||
m_queueLength = 0; | ||
} | ||
else | ||
{ | ||
/* Otherwise discard as requested by n */ | ||
m_queueLength -= n; | ||
} | ||
} | ||
|
||
/* Create a new redisContext, SELECT DB and SUBSCRIBE */ | ||
void RedisSelect::subscribe(DBConnector* db, const std::string &channelName) | ||
{ | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -88,7 +88,7 @@ bool SubscriberStateTable::hasData() | |
|
||
bool SubscriberStateTable::hasCachedData() | ||
{ | ||
return m_buffer.size() > 1 || m_keyspace_event_buffer.size() > 1; | ||
return true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It's default implementation in the base class. We could remove whole method. |
||
} | ||
|
||
void SubscriberStateTable::pops(deque<KeyOpFieldsValuesTuple> &vkco, const string& /*prefix*/) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -21,7 +21,6 @@ using namespace swss; | |
static const string dbhost = "localhost"; | ||
static const int dbport = 6379; | ||
static const string testTableName = "UT_REDIS_TABLE"; | ||
static const string testTableName2 = "UT_REDIS_TABLE2"; | ||
|
||
static inline int getMaxFields(int i) | ||
{ | ||
|
@@ -431,92 +430,3 @@ TEST(SubscriberStateTable, one_producer_multiple_subscriber) | |
} | ||
cout << endl << "Done." << endl; | ||
} | ||
|
||
TEST(SubscriberStateTable, cachedData) | ||
{ | ||
clearDB(); | ||
|
||
/* Prepare init data */ | ||
int index = 0; | ||
int maxNumOfFields = 2; | ||
|
||
DBConnector db(TEST_DB, dbhost, dbport, 0); | ||
Table p(&db, testTableName); | ||
string key1 = "TheKey1"; | ||
/* Set operation */ | ||
{ | ||
vector<FieldValueTuple> fields; | ||
for (int j = 0; j < maxNumOfFields; j++) | ||
{ | ||
FieldValueTuple t(field(index, j), value(index, j)); | ||
fields.push_back(t); | ||
} | ||
p.set(key1, fields); | ||
} | ||
|
||
Table p2(&db, testTableName2); | ||
string key2 = "TheKey2"; | ||
/* Set operation */ | ||
{ | ||
vector<FieldValueTuple> fields; | ||
for (int j = 0; j < maxNumOfFields; j++) | ||
{ | ||
FieldValueTuple t(field(index, j), value(index, j)); | ||
fields.push_back(t); | ||
} | ||
p2.set(key2, fields); | ||
} | ||
|
||
/* Prepare subscriber */ | ||
SubscriberStateTable c1(&db, testTableName); | ||
SubscriberStateTable c2(&db, testTableName2); | ||
Select cs; | ||
Selectable *selectcs; | ||
cs.addSelectable(&c1); | ||
cs.addSelectable(&c2); | ||
|
||
/* Pop operation and check CachedSelectable */ | ||
{ | ||
string key = key1; | ||
int ret = cs.select(&selectcs); | ||
EXPECT_EQ(ret, Select::OBJECT); | ||
KeyOpFieldsValuesTuple kco; | ||
if (selectcs == &c1) | ||
{ | ||
c1.pop(kco); | ||
} | ||
else | ||
{ | ||
c2.pop(kco); | ||
key = key2; | ||
} | ||
|
||
EXPECT_EQ(kfvKey(kco), key); | ||
EXPECT_EQ(kfvOp(kco), "SET"); | ||
|
||
/* There is one cached selectable left */ | ||
bool r = cs.isQueueEmpty(); | ||
EXPECT_FALSE(r); | ||
|
||
ret = cs.select(&selectcs); | ||
EXPECT_EQ(ret, Select::OBJECT); | ||
if (key == key1) | ||
{ | ||
EXPECT_TRUE(selectcs == &c2); | ||
key = key2; | ||
c2.pop(kco); | ||
} | ||
else | ||
{ | ||
EXPECT_TRUE(selectcs == &c1); | ||
key = key1; | ||
c1.pop(kco); | ||
} | ||
|
||
EXPECT_EQ(kfvKey(kco), key); | ||
EXPECT_EQ(kfvOp(kco), "SET"); | ||
/* No cached selectable left */ | ||
r = cs.isQueueEmpty(); | ||
EXPECT_TRUE(r); | ||
} | ||
} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why this test was removed? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The base class has the same implementation. It doesn't need to be implemented here.