Skip to content

Commit c59dafc

Browse files
authored
Merge pull request #239 from dave-tucker/fix-server
cache: Fix ApplyModifications for pointer fields
2 parents cd95f2d + 1ce1d52 commit c59dafc

File tree

3 files changed

+65
-9
lines changed

3 files changed

+65
-9
lines changed

cache/cache.go

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -780,6 +780,7 @@ func (t *TableCache) CreateModel(tableName string, row *ovsdb.Row, uuid string)
780780
}
781781

782782
// ApplyModifications applies the contents of a RowUpdate2.Modify to a model
783+
// nolint: gocyclo
783784
func (t *TableCache) ApplyModifications(tableName string, base model.Model, update ovsdb.Row) error {
784785
table := t.mapper.Schema.Table(tableName)
785786
if table == nil {
@@ -797,19 +798,29 @@ func (t *TableCache) ApplyModifications(tableName string, base model.Model, upda
797798
if k == "_uuid" {
798799
continue
799800
}
800-
value, err := ovsdb.OvsToNative(schema.Column(k), v)
801+
802+
current, err := info.FieldByColumn(k)
803+
if err != nil {
804+
return err
805+
}
806+
807+
var value interface{}
808+
value, err = ovsdb.OvsToNative(schema.Column(k), v)
809+
// we can overflow the max of a set with min: 0, max: 1 here because of the update2/update3 notation
810+
// which to replace "foo" with "bar" would send a set with ["foo", "bar"]
811+
if err != nil && schema.Column(k).Type == ovsdb.TypeSet && schema.Column(k).TypeObj.Max() == 1 {
812+
value, err = ovsdb.OvsToNativeSlice(schema.Column(k).TypeObj.Key.Type, v)
813+
}
801814
if err != nil {
802815
return err
803816
}
804817
nv := reflect.ValueOf(value)
805818

806-
switch nv.Kind() {
819+
switch reflect.ValueOf(current).Kind() {
807820
case reflect.Slice, reflect.Array:
808821
// The difference between two sets are all elements that only belong to one of the sets.
809-
810822
// Iterate new values
811823
for i := 0; i < nv.Len(); i++ {
812-
813824
// search for match in base values
814825
baseValue, err := info.FieldByColumn(k)
815826
if err != nil {
@@ -837,7 +848,30 @@ func (t *TableCache) ApplyModifications(tableName string, base model.Model, upda
837848
}
838849
}
839850
}
840-
851+
case reflect.Ptr:
852+
// if NativeToOVS was successful, then simply assign
853+
if nv.Type() == reflect.ValueOf(current).Type() {
854+
err = info.SetField(k, nv.Interface())
855+
return err
856+
}
857+
// With a pointer type, an update value could be a set with 2 elements [old, new]
858+
if nv.Len() != 2 {
859+
panic("expected a slice with 2 elements")
860+
}
861+
// the new value is the value in the slice which isn't equal to the existing string
862+
for i := 0; i < nv.Len(); i++ {
863+
baseValue, err := info.FieldByColumn(k)
864+
if err != nil {
865+
return err
866+
}
867+
bv := reflect.ValueOf(baseValue)
868+
if nv.Index(i) != bv {
869+
err = info.SetField(k, nv.Index(i).Addr().Interface())
870+
if err != nil {
871+
return err
872+
}
873+
}
874+
}
841875
case reflect.Map:
842876
// The difference between two maps are all key-value pairs whose keys appears in only one of the maps,
843877
// plus the key-value pairs whose keys appear in both maps but with different values.

cache/cache_test.go

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,9 @@ func TestTableCacheApplyModifications(t *testing.T) {
11791179
Set []string `ovsdb:"set"`
11801180
Map map[string]string `ovsdb:"map"`
11811181
Map2 map[string]string `ovsdb:"map2"`
1182+
Ptr *string `ovsdb:"ptr"`
11821183
}
1184+
aEmptySet, _ := ovsdb.NewOvsSet([]string{})
11831185
aFooSet, _ := ovsdb.NewOvsSet([]string{"foo"})
11841186
aFooBarSet, _ := ovsdb.NewOvsSet([]string{"foo", "bar"})
11851187
aFooMap, _ := ovsdb.NewOvsMap(map[string]string{"foo": "bar"})
@@ -1188,6 +1190,10 @@ func TestTableCacheApplyModifications(t *testing.T) {
11881190
"bar": "baz",
11891191
"baz": "quux",
11901192
})
1193+
wallace := "wallace"
1194+
aWallaceSet, _ := ovsdb.NewOvsSet([]string{wallace})
1195+
gromit := "gromit"
1196+
aWallaceGromitSet, _ := ovsdb.NewOvsSet([]string{wallace, gromit})
11911197
tests := []struct {
11921198
name string
11931199
update ovsdb.Row
@@ -1224,7 +1230,6 @@ func TestTableCacheApplyModifications(t *testing.T) {
12241230
&testDBModel{Set: []string{"foo"}},
12251231
&testDBModel{Set: []string{"bar"}},
12261232
},
1227-
12281233
{
12291234
"replace map value",
12301235
ovsdb.Row{"map": aFooMap},
@@ -1252,6 +1257,24 @@ func TestTableCacheApplyModifications(t *testing.T) {
12521257
Map2: map[string]string{"foo": "bar"},
12531258
},
12541259
},
1260+
{
1261+
"set optional value",
1262+
ovsdb.Row{"ptr": aWallaceSet},
1263+
&testDBModel{Ptr: nil},
1264+
&testDBModel{Ptr: &wallace},
1265+
},
1266+
{
1267+
"replace optional value",
1268+
ovsdb.Row{"ptr": aWallaceGromitSet},
1269+
&testDBModel{Ptr: &wallace},
1270+
&testDBModel{Ptr: &gromit},
1271+
},
1272+
{
1273+
"delete optional value",
1274+
ovsdb.Row{"ptr": aEmptySet},
1275+
&testDBModel{Ptr: &wallace},
1276+
&testDBModel{Ptr: nil},
1277+
},
12551278
}
12561279
for _, tt := range tests {
12571280
t.Run(tt.name, func(t *testing.T) {
@@ -1268,7 +1291,8 @@ func TestTableCacheApplyModifications(t *testing.T) {
12681291
"value": { "type": "string" },
12691292
"set": { "type": { "key": { "type": "string" }, "min": 0, "max": "unlimited" } },
12701293
"map": { "type": { "key": "string", "max": "unlimited", "min": 0, "value": "string" } },
1271-
"map2": { "type": { "key": "string", "max": "unlimited", "min": 0, "value": "string" } }
1294+
"map2": { "type": { "key": "string", "max": "unlimited", "min": 0, "value": "string" } },
1295+
"ptr": { "type": { "key": { "type": "string" }, "min": 0, "max": 1 } }
12721296
}
12731297
}
12741298
}

ovsdb/updates2.go

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,8 +81,6 @@ func (r *RowUpdate2) Merge(new *RowUpdate2) {
8181
oMap.GoMap[newK] = newV
8282
}
8383
}
84-
default:
85-
panic("ARGH!")
8684
}
8785
}
8886
}

0 commit comments

Comments
 (0)