[[ noreturn ]] void Logger::settingThread() { Select select; DBConnector db(LOGLEVEL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); std::vector<std::shared_ptr<ConsumerStateTable>> selectables(m_settingChangeObservers.size()); for (const auto& i : m_settingChangeObservers) { std::shared_ptr<ConsumerStateTable> table = std::make_shared<ConsumerStateTable>(&db, i.first); selectables.push_back(table); select.addSelectable(table.get()); } while(true) { Selectable *selectable = nullptr; int ret = select.select(&selectable); if (ret == Select::ERROR) { SWSS_LOG_NOTICE("%s select error %s", __PRETTY_FUNCTION__, strerror(errno)); continue; } KeyOpFieldsValuesTuple koValues; dynamic_cast<ConsumerStateTable *>(selectable)->pop(koValues); std::string key = kfvKey(koValues), op = kfvOp(koValues); if ((op != SET_COMMAND) || (m_settingChangeObservers.find(key) == m_settingChangeObservers.end())) { continue; } auto values = kfvFieldsValues(koValues); for (const auto& i : values) { const std::string &field = fvField(i), &value = fvValue(i); if ((field == DAEMON_LOGLEVEL) && (value != m_currentPrios[key])) { m_currentPrios[key] = value; m_settingChangeObservers[key].first(key, value); } else if ((field == DAEMON_LOGOUTPUT) && (value != m_currentOutputs[key])) { m_currentOutputs[key] = value; m_settingChangeObservers[key].second(key, value); } break; } } }
TEST(ConsumerStateTable, set_del) { clearDB(); /* Prepare producer */ int index = 0; string tableName = "UT_REDIS_THREAD_" + to_string(index); DBConnector db(TEST_VIEW, "localhost", 6379, 0); ProducerStateTable p(&db, tableName); string key = "TheKey"; int maxNumOfFields = 2; /* Set operation */ { vector<FieldValueTuple> fields; for (int j = 0; j < maxNumOfFields; j++) { FieldValueTuple t(field(j), value(j)); fields.push_back(t); } p.set(key, fields); } /* Del operation */ p.del(key); /* Prepare consumer */ ConsumerStateTable c(&db, tableName); Select cs; Selectable *selectcs; cs.addSelectable(&c); int tmpfd; /* First pop operation */ { int ret = cs.select(&selectcs, &tmpfd); EXPECT_TRUE(ret == Select::OBJECT); KeyOpFieldsValuesTuple kco; c.pop(kco); EXPECT_TRUE(kfvKey(kco) == key); EXPECT_TRUE(kfvOp(kco) == "DEL"); auto fvs = kfvFieldsValues(kco); EXPECT_EQ(fvs.size(), 0U); } /* Second select operation */ { int ret = cs.select(&selectcs, &tmpfd, 1000); EXPECT_TRUE(ret == Select::TIMEOUT); } }
int main(int argc, char **argv) { swss::Logger::linkToDbNative("fpmsyncd"); DBConnector db(APPL_DB, DBConnector::DEFAULT_UNIXSOCKET, 0); RedisPipeline pipeline(&db); RouteSync sync(&pipeline); NetDispatcher::getInstance().registerMessageHandler(RTM_NEWROUTE, &sync); NetDispatcher::getInstance().registerMessageHandler(RTM_DELROUTE, &sync); while (1) { try { FpmLink fpm; Select s; cout << "Waiting for connection..." << endl; fpm.accept(); cout << "Connected!" << endl; s.addSelectable(&fpm); while (true) { Selectable *temps; int tempfd; /* Reading FPM messages forever (and calling "readMe" to read them) */ s.select(&temps, &tempfd); pipeline.flush(); SWSS_LOG_DEBUG("Pipeline flushed"); } } catch (FpmLink::FpmConnectionClosedException &e) { cout << "Connection lost, reconnecting..." << endl; } catch (const exception& e) { cout << "Exception \"" << e.what() << "\" had been thrown in deamon" << endl; return 0; } } return 1; }
static void consumerWorker(int index) { string tableName = "UT_REDIS_THREAD_" + to_string(index); DBConnector db(TEST_VIEW, "localhost", 6379, 0); ConsumerStateTable c(&db, tableName); Select cs; Selectable *selectcs; int tmpfd; int numberOfKeysSet = 0; int numberOfKeyDeleted = 0; int ret, i = 0; KeyOpFieldsValuesTuple kco; cs.addSelectable(&c); while ((ret = cs.select(&selectcs, &tmpfd)) == Select::OBJECT) { c.pop(kco); if (kfvOp(kco) == "SET") { numberOfKeysSet++; validateFields(kfvKey(kco), kfvFieldsValues(kco)); } else if (kfvOp(kco) == "DEL") { numberOfKeyDeleted++; } if ((i++ % 100) == 0) cout << "-" << flush; if (numberOfKeyDeleted == NUMBER_OF_OPS) break; } EXPECT_TRUE(numberOfKeysSet <= numberOfKeyDeleted); EXPECT_EQ(ret, Selectable::DATA); }
TEST(ConsumerStateTable, multitable) { DBConnector db(TEST_VIEW, "localhost", 6379, 0); ConsumerStateTable *consumers[NUMBER_OF_THREADS]; thread *producerThreads[NUMBER_OF_THREADS]; KeyOpFieldsValuesTuple kco; Select cs; int numberOfKeysSet = 0; int numberOfKeyDeleted = 0; int ret = 0, i; clearDB(); cout << "Starting " << NUMBER_OF_THREADS*2 << " producers and consumers on redis, using single thread for consumers and thread per producer" << endl; /* Starting the consumer before the producer */ for (i = 0; i < NUMBER_OF_THREADS; i++) { consumers[i] = new ConsumerStateTable(&db, string("UT_REDIS_THREAD_") + to_string(i)); producerThreads[i] = new thread(producerWorker, i); } for (i = 0; i < NUMBER_OF_THREADS; i++) cs.addSelectable(consumers[i]); while (1) { Selectable *is; int fd; ret = cs.select(&is, &fd); EXPECT_EQ(ret, Select::OBJECT); ((ConsumerStateTable *)is)->pop(kco); if (kfvOp(kco) == "SET") { numberOfKeysSet++; validateFields(kfvKey(kco), kfvFieldsValues(kco)); } else if (kfvOp(kco) == "DEL") { numberOfKeyDeleted++; if ((numberOfKeyDeleted % 100) == 0) cout << "-" << flush; } if (numberOfKeyDeleted == NUMBER_OF_OPS * NUMBER_OF_THREADS) break; } EXPECT_TRUE(numberOfKeysSet <= numberOfKeyDeleted); /* Making sure threads stops execution */ for (i = 0; i < NUMBER_OF_THREADS; i++) { producerThreads[i]->join(); delete consumers[i]; delete producerThreads[i]; } cout << endl << "Done." << endl; }
TEST(ConsumerStateTable, singlethread) { clearDB(); int index = 0; string tableName = "UT_REDIS_THREAD_" + to_string(index); DBConnector db(TEST_VIEW, "localhost", 6379, 0); ProducerStateTable p(&db, tableName); for (int i = 0; i < NUMBER_OF_OPS; i++) { vector<FieldValueTuple> fields; int maxNumOfFields = getMaxFields(i); for (int j = 0; j < maxNumOfFields; j++) { FieldValueTuple t(field(j), value(j)); fields.push_back(t); } if ((i % 100) == 0) cout << "+" << flush; p.set(key(i), fields); } ConsumerStateTable c(&db, tableName); Select cs; Selectable *selectcs; int tmpfd; int ret, i = 0; KeyOpFieldsValuesTuple kco; cs.addSelectable(&c); int numberOfKeysSet = 0; while ((ret = cs.select(&selectcs, &tmpfd)) == Select::OBJECT) { c.pop(kco); EXPECT_TRUE(kfvOp(kco) == "SET"); numberOfKeysSet++; validateFields(kfvKey(kco), kfvFieldsValues(kco)); if ((i++ % 100) == 0) cout << "-" << flush; if (numberOfKeysSet == NUMBER_OF_OPS) break; } for (i = 0; i < NUMBER_OF_OPS; i++) { p.del(key(i)); if ((i % 100) == 0) cout << "+" << flush; } int numberOfKeyDeleted = 0; while ((ret = cs.select(&selectcs, &tmpfd)) == Select::OBJECT) { c.pop(kco); EXPECT_TRUE(kfvOp(kco) == "DEL"); numberOfKeyDeleted++; if ((i++ % 100) == 0) cout << "-" << flush; if (numberOfKeyDeleted == NUMBER_OF_OPS) break; } EXPECT_TRUE(numberOfKeysSet <= numberOfKeyDeleted); EXPECT_EQ(ret, Selectable::DATA); cout << "Done. Waiting for all job to finish " << NUMBER_OF_OPS << " jobs." << endl; cout << endl << "Done." << endl; }
TEST(ConsumerStateTable, double_set) { clearDB(); /* Prepare producer */ int index = 0; string tableName = "UT_REDIS_THREAD_" + to_string(index); DBConnector db(TEST_VIEW, "localhost", 6379, 0); ProducerStateTable p(&db, tableName); string key = "TheKey"; int maxNumOfFields = 2; /* First set operation */ { vector<FieldValueTuple> fields; for (int j = 0; j < maxNumOfFields; j++) { FieldValueTuple t(field(j), value(j)); fields.push_back(t); } p.set(key, fields); } /* Second set operation */ { vector<FieldValueTuple> fields; for (int j = 0; j < maxNumOfFields * 2; j += 2) { FieldValueTuple t(field(j), value(j)); fields.push_back(t); } p.set(key, fields); } /* Prepare consumer */ ConsumerStateTable c(&db, tableName); Select cs; Selectable *selectcs; cs.addSelectable(&c); int tmpfd; /* First pop operation */ { int ret = cs.select(&selectcs, &tmpfd); EXPECT_TRUE(ret == Select::OBJECT); KeyOpFieldsValuesTuple kco; c.pop(kco); EXPECT_TRUE(kfvKey(kco) == key); EXPECT_TRUE(kfvOp(kco) == "SET"); auto fvs = kfvFieldsValues(kco); EXPECT_EQ(fvs.size(), (unsigned int)(maxNumOfFields + maxNumOfFields/2)); map<string, string> mm; for (auto fv: fvs) { mm[fvField(fv)] = fvValue(fv); } for (int j = 0; j < maxNumOfFields; j++) { EXPECT_EQ(mm[field(j)], value(j)); } for (int j = 0; j < maxNumOfFields * 2; j += 2) { EXPECT_EQ(mm[field(j)], value(j)); } } /* Second select operation */ { int ret = cs.select(&selectcs, &tmpfd, 1000); EXPECT_TRUE(ret == Select::TIMEOUT); } }