Skip to content

Commit bde1f5f

Browse files
committed
ensure cache is consistent before reading data
Signed-off-by: zhangzujian <zhangzujian.7@gmail.com>
1 parent a88ba3f commit bde1f5f

2 files changed

Lines changed: 53 additions & 15 deletions

File tree

client/api.go

Lines changed: 22 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,11 @@ type API interface {
2121
// If it has a capacity != 0, only 'capacity' elements will be filled in
2222
List(ctx context.Context, result any) error
2323

24+
// Create a Conditional API from a Function that is used to filter cached data
25+
// The function must accept a Model implementation and return a boolean. E.g:
26+
// ConditionFromFunc(func(l *LogicalSwitch) bool { return l.Enabled })
27+
WherePredict(ctx context.Context, predicate any) (ConditionalAPI, error)
28+
2429
// Create a Conditional API from a Function that is used to filter cached data
2530
// The function must accept a Model implementation and return a boolean. E.g:
2631
// ConditionFromFunc(func(l *LogicalSwitch) bool { return l.Enabled })
@@ -139,8 +144,10 @@ func (a api) List(_ context.Context, result any) error {
139144
}
140145

141146
if a.cond != nil && a.cond.Table() != table {
142-
return &ErrWrongType{resultPtr.Type(),
143-
fmt.Sprintf("Table derived from input type (%s) does not match Table from Condition (%s)", table, a.cond.Table())}
147+
return &ErrWrongType{
148+
resultPtr.Type(),
149+
fmt.Sprintf("Table derived from input type (%s) does not match Table from Condition (%s)", table, a.cond.Table()),
150+
}
144151
}
145152

146153
tableCache := a.cache.Table(table)
@@ -194,6 +201,11 @@ func (a api) WhereAll(m model.Model, cond ...model.Condition) ConditionalAPI {
194201
return newConditionalAPI(a.cache, a.conditionFromExplicitConditions(true, m, cond...), a.logger, a.validateModel)
195202
}
196203

204+
// WherePredict returns a conditionalAPI based a Predicate
205+
func (a api) WherePredict(ctx context.Context, predicate interface{}) (ConditionalAPI, error) {
206+
return newConditionalAPI(a.cache, a.conditionFromFunc(predicate), a.logger, a.validateModel), nil
207+
}
208+
197209
// WhereCache returns a conditionalAPI based a Predicate
198210
func (a api) WhereCache(predicate any) ConditionalAPI {
199211
return newConditionalAPI(a.cache, a.conditionFromFunc(predicate), a.logger, a.validateModel)
@@ -321,7 +333,6 @@ func (a api) Create(models ...model.Model) ([]ovsdb.Operation, error) {
321333
namedUUID = tmpUUID
322334
} else if ovsdb.IsValidUUID(tmpUUID) {
323335
realUUID = tmpUUID
324-
325336
}
326337
} else {
327338
return nil, fmt.Errorf("error accessing _uuid field: %w", err)
@@ -607,14 +618,18 @@ func (a api) getTableFromFunc(predicate any) (string, error) {
607618
modelInterface := reflect.TypeOf((*model.Model)(nil)).Elem()
608619
modelType := predType.In(0)
609620
if !modelType.Implements(modelInterface) {
610-
return "", &ErrWrongType{predType,
611-
fmt.Sprintf("Type %s does not implement Model interface", modelType.String())}
621+
return "", &ErrWrongType{
622+
predType,
623+
fmt.Sprintf("Type %s does not implement Model interface", modelType.String()),
624+
}
612625
}
613626

614627
table := a.cache.DatabaseModel().FindTable(modelType)
615628
if table == "" {
616-
return "", &ErrWrongType{predType,
617-
fmt.Sprintf("Model %s not found in Database Model", modelType.String())}
629+
return "", &ErrWrongType{
630+
predType,
631+
fmt.Sprintf("Model %s not found in Database Model", modelType.String()),
632+
}
618633
}
619634
return table, nil
620635
}

client/client.go

Lines changed: 31 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1084,7 +1084,7 @@ func (o *ovsdbClient) monitor(ctx context.Context, cookie MonitorCookie, reconne
10841084
return err
10851085
}
10861086

1087-
// Echo tests the liveness of the OVSDB connetion
1087+
// Echo tests the liveness of the OVSDB connection
10881088
func (o *ovsdbClient) Echo(ctx context.Context) error {
10891089
args := ovsdb.NewEchoArgs()
10901090
var reply []any
@@ -1369,15 +1369,21 @@ func isCacheConsistent(db *database) bool {
13691369

13701370
// best effort to ensure cache is in a good state for reading. RLocks the
13711371
// database's cache before returning; caller must always unlock.
1372-
func waitForCacheConsistent(ctx context.Context, db *database, logger *logr.Logger, dbName string) {
1372+
func (o *ovsdbClient) waitForCacheConsistent(ctx context.Context, db *database, logger *logr.Logger, dbName string) error {
13731373
if !hasMonitors(db) {
13741374
db.cacheMutex.RLock()
1375-
return
1375+
return nil
1376+
}
1377+
1378+
if err := o.Echo(ctx); err != nil {
1379+
db.cacheMutex.RLock()
1380+
return err
13761381
}
1382+
13771383
// Check immediately as a fastpath
13781384
db.cacheMutex.RLock()
13791385
if isCacheConsistent(db) {
1380-
return
1386+
return nil
13811387
}
13821388
db.cacheMutex.RUnlock()
13831389

@@ -1389,11 +1395,11 @@ func waitForCacheConsistent(ctx context.Context, db *database, logger *logr.Logg
13891395
logger.V(3).Info("warning: unable to ensure cache consistency for reading",
13901396
"database", dbName)
13911397
db.cacheMutex.RLock()
1392-
return
1398+
return nil
13931399
case <-ticker.C:
13941400
db.cacheMutex.RLock()
13951401
if isCacheConsistent(db) {
1396-
return
1402+
return nil
13971403
}
13981404
db.cacheMutex.RUnlock()
13991405
}
@@ -1413,8 +1419,11 @@ func hasMonitors(db *database) bool {
14131419
// Get implements the API interface's Get function
14141420
func (o *ovsdbClient) Get(ctx context.Context, model model.Model) error {
14151421
primaryDB := o.primaryDB()
1416-
waitForCacheConsistent(ctx, primaryDB, o.logger, o.primaryDBName)
1422+
err := o.waitForCacheConsistent(ctx, primaryDB, o.logger, o.primaryDBName)
14171423
defer primaryDB.cacheMutex.RUnlock()
1424+
if err != nil {
1425+
return err
1426+
}
14181427
return primaryDB.api.Get(ctx, model)
14191428
}
14201429

@@ -1426,8 +1435,11 @@ func (o *ovsdbClient) Create(models ...model.Model) ([]ovsdb.Operation, error) {
14261435
// List implements the API interface's List function
14271436
func (o *ovsdbClient) List(ctx context.Context, result any) error {
14281437
primaryDB := o.primaryDB()
1429-
waitForCacheConsistent(ctx, primaryDB, o.logger, o.primaryDBName)
1438+
err := o.waitForCacheConsistent(ctx, primaryDB, o.logger, o.primaryDBName)
14301439
defer primaryDB.cacheMutex.RUnlock()
1440+
if err != nil {
1441+
return err
1442+
}
14311443
return primaryDB.api.List(ctx, result)
14321444
}
14331445

@@ -1446,6 +1458,17 @@ func (o *ovsdbClient) WhereAll(m model.Model, conditions ...model.Condition) Con
14461458
return o.primaryDB().api.WhereAll(m, conditions...)
14471459
}
14481460

1461+
// WherePredict implements the API interface's WherePredict function
1462+
func (o *ovsdbClient) WherePredict(ctx context.Context, predicate interface{}) (ConditionalAPI, error) {
1463+
primaryDB := o.primaryDB()
1464+
err := o.waitForCacheConsistent(ctx, primaryDB, o.logger, o.primaryDBName)
1465+
defer primaryDB.cacheMutex.RUnlock()
1466+
if err != nil {
1467+
return nil, err
1468+
}
1469+
return o.primaryDB().api.WhereCache(predicate), nil
1470+
}
1471+
14491472
// WhereCache implements the API interface's WhereCache function
14501473
func (o *ovsdbClient) WhereCache(predicate any) ConditionalAPI {
14511474
return o.primaryDB().api.WhereCache(predicate)

0 commit comments

Comments
 (0)