Skip to content

Commit

Permalink
Merge "Handling for OVSDB Connection close"
Browse files Browse the repository at this point in the history
  • Loading branch information
Zuul authored and opencontrail-ci-admin committed Feb 3, 2015
2 parents efab3c9 + b0bdf92 commit 645189a
Show file tree
Hide file tree
Showing 23 changed files with 595 additions and 145 deletions.
11 changes: 11 additions & 0 deletions src/ksync/README
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,10 @@ KSyncDBEntry:
Implementation of KSyncEntry associated with a DBEntry. The infrastructure will
register to the DBTable as a client. The events to state-machine are automatically triggerred based on Notification from DBTable.

In Cases where definition of Key for DBTable entries and KSyncDbEntries is different,
it also allows handling of Single KSync Entry mapping to multiple DBTable Entries
using duplicate entry list.

KSyncNetlinkDBEntry:
--------------------
Implementation of KSyncDBEntry associated with a DBEntry. Messages to kernel are
Expand All @@ -96,3 +100,10 @@ KSyncNetlinkEntry :
Implementation of KSyncEntry where objects are written to kernel using Netlink
ASIO sockets. It does not work on DBTable notifications. It is responsibility
of application to trigger events to the state-machine.

KSyncObjectManager:
-------------------
It provides following event functionality for KSync Objects
- UNREGISTER : to delete given KSync Object in context of KSync Task
- DELETE : to trigger delete for all teh KSync Entries present in
the given KSync Object
2 changes: 1 addition & 1 deletion src/ksync/ksync_entry.h
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ class KSyncDBEntry : public KSyncEntry, public DBState {

KSyncDBEntry() : KSyncEntry(), DBState() { db_entry_ = NULL; };
KSyncDBEntry(uint32_t index) : KSyncEntry(index), DBState() { db_entry_ = NULL; };
virtual ~KSyncDBEntry() { };
virtual ~KSyncDBEntry() { assert(dup_entry_list_.empty()); }

// Check if object is in-sync with kernel.
// Return true if object needs sync. Else return false
Expand Down
76 changes: 74 additions & 2 deletions src/ksync/ksync_object.cc
Original file line number Diff line number Diff line change
Expand Up @@ -33,11 +33,13 @@ KSyncObjectManager *KSyncObjectManager::singleton_;
std::auto_ptr<KSyncEntry> KSyncObjectManager::default_defer_entry_;
bool KSyncDebug::debug_;

KSyncObject::KSyncObject() : need_index_(false), index_table_() {
KSyncObject::KSyncObject() : need_index_(false), index_table_(),
delete_scheduled_(false) {
}

KSyncObject::KSyncObject(int max_index) :
need_index_(true), index_table_(max_index) {
need_index_(true), index_table_(max_index),
delete_scheduled_(false) {
}

KSyncObject::~KSyncObject() {
Expand Down Expand Up @@ -72,6 +74,9 @@ KSyncEntry *KSyncObject::Next(const KSyncEntry *entry) const {
return NULL;
}
KSyncEntry *KSyncObject::CreateImpl(const KSyncEntry *key) {
// should not create an entry while scheduled for deletion
assert(delete_scheduled_ == false);

KSyncEntry *entry;
if (need_index_) {
entry = Alloc(key, index_table_.Alloc());
Expand Down Expand Up @@ -200,6 +205,15 @@ void KSyncDBObject::CleanupOnDel(KSyncEntry *entry) {
kentry->GetDBEntry()->ClearState(table_, id_);
kentry->SetDBEntry(NULL);
}

if (delete_scheduled()) {
// we are in cleanup process remove all duplicate entries
while (kentry->dup_entry_list_.empty() == false) {
// and clear db entry state
kentry->dup_entry_list_.front()->ClearState(table_, id_);
kentry->dup_entry_list_.pop_front();
}
}
}

// DBTable notification handler.
Expand All @@ -214,6 +228,11 @@ void KSyncDBObject::Notify(DBTablePartBase *partition, DBEntryBase *e) {
KSyncDBEntry *ksync = static_cast<KSyncDBEntry *>(state);
DBFilterResp resp = DBFilterAccept;

// cleanup is in-process, ignore All db notifications.
if (delete_scheduled()) {
return;
}

// Trigger DB Filter callback only for ADD/CHANGE, since we need to handle
// cleanup for delete anyways.
if (!entry->IsDeleted()) {
Expand Down Expand Up @@ -1169,6 +1188,44 @@ bool KSyncObjectManager::Process(KSyncObjectEvent *event) {
case KSyncObjectEvent::UNREGISTER:
delete event->obj_;
break;
case KSyncObjectEvent::DELETE:
{
int count = 0;
KSyncEntry *entry;
if (event->ref_.get() == NULL) {
event->obj_->set_delete_scheduled();
if (event->obj_->IsEmpty()) {
// trigger explicit empty table callback for client to
// complete deletion of object in KSync Context.
event->obj_->EmptyTable();
break;
}
// get the first entry to start with
entry = event->obj_->Next(NULL);
} else {
entry = event->ref_.get();
}

while (entry != NULL) {
KSyncEntry *next_entry = event->obj_->Next(entry);
count++;
if (entry->IsDeleted() == false) {
// trigger delete if entry is not marked delete already.
event->obj_->SafeNotifyEvent(entry, KSyncEntry::DEL_REQ);
}

if (count == kMaxEntriesProcess && next_entry != NULL) {
// update reference with which entry to start with
// in next iteration.
event->ref_ = next_entry;
// yeild and re-enqueue event for processing later.
event_queue_->Enqueue(event);
return false;
}
entry = next_entry;
}
break;
}
default:
assert(0);
}
Expand Down Expand Up @@ -1208,6 +1265,21 @@ void KSyncObjectManager::Shutdown() {
singleton_ = NULL;
}

// Create a KSync Object event to trigger Delete of all the KSync Entries
// present in the given object.
// Once the delete is scheduled new entry creation is not allowed for this
// object and EmptyTable callback is trigger when all the entries of given
// object are cleaned up. As part of which client can delete the object.
//
// This API can be used to clean up KSync objects irrespective of config
// or oper tables

void KSyncObjectManager::Delete(KSyncObject *object) {
KSyncObjectEvent *event = new KSyncObjectEvent(object,
KSyncObjectEvent::DELETE);
Enqueue(event);
}

// Create a dummy KSync Entry. This entry will all ways be in deferred state
// Any back-ref added to it will never get resolved.
// Can be used to defer an incomplete entry
Expand Down
14 changes: 13 additions & 1 deletion src/ksync/ksync_object.h
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,10 @@ class KSyncObject {

virtual bool DoEventTrace(void) { return true; }
static void Shutdown();

void set_delete_scheduled() { delete_scheduled_ = true;}
bool delete_scheduled() { return delete_scheduled_;}

protected:
// Create an entry with default state. Used internally
KSyncEntry *CreateImpl(const KSyncEntry *key);
Expand Down Expand Up @@ -152,6 +156,9 @@ class KSyncObject {
bool need_index_;
// Index table for KSyncObject
KSyncIndexTable index_table_;
// scheduled for deletion
bool delete_scheduled_;

DISALLOW_COPY_AND_ASSIGN(KSyncObject);
};

Expand Down Expand Up @@ -214,17 +221,21 @@ class KSyncDBObject : public KSyncObject {
struct KSyncObjectEvent {
enum Event {
UNKNOWN,
UNREGISTER
UNREGISTER,
DELETE,
};
KSyncObjectEvent(KSyncObject *obj, Event event) :
obj_(obj), event_(event) {
}
KSyncEntry::KSyncEntryPtr ref_;
KSyncObject *obj_;
Event event_;
};

class KSyncObjectManager {
public:
static const int kMaxEntriesProcess = 100;

KSyncObjectManager();
~KSyncObjectManager();
bool Process(KSyncObjectEvent *event);
Expand All @@ -233,6 +244,7 @@ class KSyncObjectManager {
static KSyncObjectManager *Init();
static void Shutdown();
static void Unregister(KSyncObject *);
void Delete(KSyncObject *);
private:
WorkQueue<KSyncObjectEvent *> *event_queue_;
static std::auto_ptr<KSyncEntry> default_defer_entry_;
Expand Down
68 changes: 67 additions & 1 deletion src/ksync/test/ksync_db_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@ class VlanTable;

VlanTable *vlan_table_;

KSyncObjectManager *object_manager;

class TestUT : public ::testing::Test {
public:
TestUT() { cout << "Creating TestTask" << endl; };
Expand Down Expand Up @@ -183,7 +185,8 @@ int VlanKSyncEntry::del_count_;

class VlanKSyncObject : public KSyncDBObject {
public:
VlanKSyncObject(DBTableBase *table) : KSyncDBObject(table) {};
VlanKSyncObject(DBTableBase *table) : KSyncDBObject(table),
is_empty_count_(0) {}

virtual KSyncEntry *Alloc(const KSyncEntry *entry, uint32_t index) {
const VlanKSyncEntry *vlan = static_cast<const VlanKSyncEntry *>(entry);
Expand All @@ -209,6 +212,9 @@ class VlanKSyncObject : public KSyncDBObject {

static VlanKSyncObject *GetKSyncObject() { return singleton_; };

virtual void EmptyTable(void) { is_empty_count_++; }
int is_empty_count_;

private:
static VlanKSyncObject *singleton_;
DISALLOW_COPY_AND_ASSIGN(VlanKSyncObject);
Expand Down Expand Up @@ -521,10 +527,70 @@ TEST_F(DBKSyncTest, OneKSyncEntryForTwoOperDBEntry) {
EXPECT_EQ(VlanKSyncEntry::GetDelCount(), 1);
}

TEST_F(DBKSyncTest, Vlan_object_delete_with_dup_entries) {
DBRequest req;
req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
req.key.reset(new Vlan::VlanKey("vlan10", 10));
req.data.reset(NULL);
itbl->Enqueue(&req);

task_util::WaitForIdle();
VlanKSyncEntry v(10);
VlanKSyncEntry *ksync_vlan =
static_cast<VlanKSyncEntry *>(VlanKSyncObject::GetKSyncObject()->Find(&v));

// check ksync entry in sync and db entry vlan 10 being in use
EXPECT_EQ(ksync_vlan->GetState(), KSyncEntry::IN_SYNC);
EXPECT_TRUE(ksync_vlan->name().compare("vlan10") == 0);

req.oper = DBRequest::DB_ENTRY_ADD_CHANGE;
req.key.reset(new Vlan::VlanKey("new_vlan10", 10));
req.data.reset(NULL);
itbl->Enqueue(&req);
task_util::WaitForIdle();

// check ksync entry in sync and db entry vlan 10 being in use
EXPECT_EQ(ksync_vlan->GetState(), KSyncEntry::IN_SYNC);
EXPECT_TRUE(ksync_vlan->name().compare("vlan10") == 0);

// fetch previous pointer and create a new vlan object.
VlanKSyncObject *vlan_obj = VlanKSyncObject::GetKSyncObject();

// trigger ksync object delete
vlan_obj->is_empty_count_ = 0;
object_manager->Delete(vlan_obj);
task_util::WaitForIdle();

EXPECT_EQ(vlan_obj->is_empty_count_, 1);

EXPECT_EQ(VlanKSyncEntry::GetAddCount(), 1);
EXPECT_EQ(VlanKSyncEntry::GetDelCount(), 1);

VlanKSyncObject::Shutdown();
VlanKSyncObject::Init(itbl);

// delete both the db entries.
req.oper = DBRequest::DB_ENTRY_DELETE;
req.key.reset(new Vlan::VlanKey("vlan10", 10));
req.data.reset(NULL);
itbl->Enqueue(&req);
task_util::WaitForIdle();

req.oper = DBRequest::DB_ENTRY_DELETE;
req.key.reset(new Vlan::VlanKey("new_vlan10", 10));
req.data.reset(NULL);
itbl->Enqueue(&req);
task_util::WaitForIdle();

EXPECT_EQ(adc_notification, 2);
EXPECT_EQ(del_notification, 2);
}

int main(int argc, char **argv) {
::testing::InitGoogleTest(&argc, argv);
LoggingInit();

object_manager = KSyncObjectManager::Init();
DB::RegisterFactory("db.test.vlan.0", &VlanTable::CreateTable);
return RUN_ALL_TESTS();
}

0 comments on commit 645189a

Please sign in to comment.