From ae0caedaac6d08e09ae740db4ee00a7fc0753a4e Mon Sep 17 00:00:00 2001 From: Minhan Xia Date: Thu, 25 Oct 2018 14:39:26 -0700 Subject: [PATCH] add util for transaction table --- pkg/neg/syncers/transaction_table.go | 78 +++++++++++++++++++ pkg/neg/syncers/transaction_table_test.go | 92 +++++++++++++++++++++++ 2 files changed, 170 insertions(+) create mode 100644 pkg/neg/syncers/transaction_table.go create mode 100644 pkg/neg/syncers/transaction_table_test.go diff --git a/pkg/neg/syncers/transaction_table.go b/pkg/neg/syncers/transaction_table.go new file mode 100644 index 0000000000..d330d49a6c --- /dev/null +++ b/pkg/neg/syncers/transaction_table.go @@ -0,0 +1,78 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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. +*/ + +package syncers + +const ( + attachOp = iota + detachOp +) + +type transactionOp int + +func (op transactionOp) String() string { + switch op { + case attachOp: + return "Attach" + case detachOp: + return "Detach" + default: + return "UnknownOperation" + } +} + +type transactionEntry struct { + // Operation represents the operation type associated with each transaction + Operation transactionOp + // NeedReconcile indicates whether the entry needs to be reconciled. + NeedReconcile bool + // Zone represents the zone of the transaction + Zone string +} + +// transactionTable records ongoing NEG API operation per endpoint +// It uses the encoded endpoint as key and associate attributes of an transaction as value +// WARNING: transactionTable is not thread safe +type transactionTable struct { + data map[string]transactionEntry +} + +func NewTransactionTable() transactionTable { + return transactionTable{ + data: make(map[string]transactionEntry), + } +} + +func (tt transactionTable) Keys() []string { + res := []string{} + for key := range tt.data { + res = append(res, key) + } + return res +} + +func (tt transactionTable) Get(key string) (transactionEntry, bool) { + ret, ok := tt.data[key] + return ret, ok +} + +func (tt transactionTable) Delete(key string) { + delete(tt.data, key) +} + +func (tt transactionTable) Put(key string, entry transactionEntry) { + tt.data[key] = entry +} diff --git a/pkg/neg/syncers/transaction_table_test.go b/pkg/neg/syncers/transaction_table_test.go new file mode 100644 index 0000000000..7d4a15528b --- /dev/null +++ b/pkg/neg/syncers/transaction_table_test.go @@ -0,0 +1,92 @@ +/* +Copyright 2018 The Kubernetes Authors. + +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. +*/ + +package syncers + +import ( + "fmt" + "testing" +) + +func TestTransactionTable(t *testing.T) { + table := NewTransactionTable() + + // Verify table are empty initially + ret := table.Keys() + if len(ret) != 0 { + t.Errorf("Expect no keys, but got %v", ret) + } + + _, ok := table.Get("non exist") + if ok { + t.Errorf("Expect ok = false, but got %v", ok) + } + + testNum := 10 + keyPrefix := "key" + zonePrefix := "zone" + testKeyMap := map[string]transactionEntry{} + + // Insert entries into transaction table + for i := 0; i < testNum; i++ { + key := fmt.Sprintf("%s%d", keyPrefix, i) + entry := transactionEntry{ + attachOp, + false, + fmt.Sprintf("%s%d", zonePrefix, i), + } + table.Put(key, entry) + testKeyMap[key] = entry + } + + verifyTable(t, table, testKeyMap) + + // Update half of the entries in the transaction table + for i := 0; i < testNum/2; i++ { + key := fmt.Sprintf("%s%d", keyPrefix, i) + newEntry := transactionEntry{ + detachOp, + true, + fmt.Sprintf("%s%d", zonePrefix, i), + } + table.Put(key, newEntry) + testKeyMap[key] = newEntry + } + + verifyTable(t, table, testKeyMap) +} + +func verifyTable(t *testing.T, table transactionTable, expectTransactionMap map[string]transactionEntry) { + keys := table.Keys() + if len(expectTransactionMap) != len(keys) { + t.Errorf("Expect keys length to be %v, but got %v", len(expectTransactionMap), len(keys)) + } + + for _, key := range keys { + entry, ok := table.Get(key) + if !ok { + t.Errorf("Expect key %q to exist in transaction table, but got %v", key, ok) + } + expectEntry, ok := expectTransactionMap[key] + if !ok { + t.Errorf("Expect key %q to exist in testKeyMap, but got %v", key, ok) + } + + if entry != expectEntry { + t.Errorf("Expect entry to be %v, but got %v", expectEntry, entry) + } + } +}