Skip to content

Commit 2308c04

Browse files
committed
firewalldb+rpcserver: refactor ListActions
Here we move the filter logic behind the interface so that our sql implementation can make use of indexes.
1 parent c92e536 commit 2308c04

File tree

6 files changed

+286
-148
lines changed

6 files changed

+286
-148
lines changed

firewalldb/action_paginator.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ type actionPaginator struct {
1616

1717
// filterFn is the filter function which we are using to determine which
1818
// actions should be included in the return list.
19-
filterFn ListActionsFilterFn
19+
filterFn listActionsFilterFn
2020

2121
// readAction is a closure which we use to read an action from the db
2222
// given a key value pair.
@@ -32,7 +32,7 @@ type actionPaginator struct {
3232
// cfg.CountAll is set).
3333
func paginateActions(cfg *ListActionsQuery, c kvdb.RCursor,
3434
readAction func(k, v []byte) (*Action, error),
35-
filterFn ListActionsFilterFn) ([]*Action, uint64, uint64, error) {
35+
filterFn listActionsFilterFn) ([]*Action, uint64, uint64, error) {
3636

3737
if cfg == nil {
3838
cfg = &ListActionsQuery{}

firewalldb/actions.go

Lines changed: 97 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ type Action struct {
7272
}
7373

7474
// ListActionsQuery can be used to tweak the query to ListActions and
75-
// ListSessionActions.
75+
// listSessionActions.
7676
type ListActionsQuery struct {
7777
// IndexOffset is index of the action to inspect.
7878
IndexOffset uint64
@@ -91,6 +91,93 @@ type ListActionsQuery struct {
9191
CountAll bool
9292
}
9393

94+
// listActionsOptions holds the options that can be used to filter the actions
95+
// that are returned by the ListActions method.
96+
type listActionOptions struct {
97+
sessionID session.ID
98+
groupID session.ID
99+
featureName string
100+
actorName string
101+
methodName string
102+
state ActionState
103+
endTime time.Time
104+
startTime time.Time
105+
}
106+
107+
// newListActionOptions creates a new listActionOptions instance with default
108+
// query values.
109+
func newListActionOptions() *listActionOptions {
110+
return &listActionOptions{}
111+
}
112+
113+
// ListActionOption is a functional option that can be used to tweak the
114+
// behaviour of the ListActions method.
115+
type ListActionOption func(*listActionOptions)
116+
117+
// WithActionSessionID is a ListActionOption that can be select all Actions
118+
// with the given session ID.
119+
func WithActionSessionID(sessionID session.ID) ListActionOption {
120+
return func(o *listActionOptions) {
121+
o.sessionID = sessionID
122+
}
123+
}
124+
125+
// WithActionGroupID is a ListActionOption that can be select all Actions with
126+
// performed under the give group ID.
127+
func WithActionGroupID(groupID session.ID) ListActionOption {
128+
return func(o *listActionOptions) {
129+
o.groupID = groupID
130+
}
131+
}
132+
133+
// WithActionStartTime is a ListActionOption that can be used to select all
134+
// Actions that were attempted after the given time.
135+
func WithActionStartTime(startTime time.Time) ListActionOption {
136+
return func(o *listActionOptions) {
137+
o.startTime = startTime
138+
}
139+
}
140+
141+
// WithActionEndTime is a ListActionOption that can be used to select all
142+
// Actions that were attempted before the given time.
143+
func WithActionEndTime(endTime time.Time) ListActionOption {
144+
return func(o *listActionOptions) {
145+
o.endTime = endTime
146+
}
147+
}
148+
149+
// WithActionFeatureName is a ListActionOption that can be used to select all
150+
// Actions that were performed by the given feature.
151+
func WithActionFeatureName(featureName string) ListActionOption {
152+
return func(o *listActionOptions) {
153+
o.featureName = featureName
154+
}
155+
}
156+
157+
// WithActionActorName is a ListActionOption that can be used to select all
158+
// Actions that were performed by the given actor.
159+
func WithActionActorName(actorName string) ListActionOption {
160+
return func(o *listActionOptions) {
161+
o.actorName = actorName
162+
}
163+
}
164+
165+
// WithActionMethodName is a ListActionOption that can be used to select all
166+
// Actions that called the given RPC method.
167+
func WithActionMethodName(methodName string) ListActionOption {
168+
return func(o *listActionOptions) {
169+
o.methodName = methodName
170+
}
171+
}
172+
173+
// WithActionState is a ListActionOption that can be used to select all Actions
174+
// that are in the given state.
175+
func WithActionState(state ActionState) ListActionOption {
176+
return func(o *listActionOptions) {
177+
o.state = state
178+
}
179+
}
180+
94181
// ActionsWriteDB is an abstraction over the Actions DB that will allow a
95182
// caller to add new actions as well as change the values of an existing action.
96183
type ActionsWriteDB interface {
@@ -174,10 +261,10 @@ var _ ActionsListDB = (*groupActionsReadDB)(nil)
174261
func (s *groupActionsReadDB) ListActions(ctx context.Context) ([]*RuleAction,
175262
error) {
176263

177-
sessionActions, err := s.db.ListGroupActions(
178-
ctx, s.groupID, func(a *Action, _ bool) (bool, bool) {
179-
return a.State == ActionStateDone, true
180-
},
264+
sessionActions, _, _, err := s.db.ListActions(
265+
ctx, nil,
266+
WithActionGroupID(s.groupID),
267+
WithActionState(ActionStateDone),
181268
)
182269
if err != nil {
183270
return nil, err
@@ -205,11 +292,11 @@ var _ ActionsListDB = (*groupFeatureActionsReadDB)(nil)
205292
func (a *groupFeatureActionsReadDB) ListActions(ctx context.Context) (
206293
[]*RuleAction, error) {
207294

208-
featureActions, err := a.db.ListGroupActions(
209-
ctx, a.groupID, func(action *Action, _ bool) (bool, bool) {
210-
return action.State == ActionStateDone &&
211-
action.FeatureName == a.featureName, true
212-
},
295+
featureActions, _, _, err := a.db.ListActions(
296+
ctx, nil,
297+
WithActionGroupID(a.groupID),
298+
WithActionState(ActionStateDone),
299+
WithActionFeatureName(a.featureName),
213300
)
214301
if err != nil {
215302
return nil, err

firewalldb/actions_kvdb.go

Lines changed: 94 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -198,19 +198,91 @@ func (db *BoltDB) SetActionState(al *ActionLocator, state ActionState,
198198
})
199199
}
200200

201-
// ListActionsFilterFn defines a function that can be used to determine if an
202-
// action should be included in a set of results or not. The reversed parameter
203-
// indicates if the actions are being traversed in reverse order or not.
204-
// The first return boolean indicates if the action should be included or not
205-
// and the second one indicates if the iteration should be stopped or not.
206-
type ListActionsFilterFn func(a *Action, reversed bool) (bool, bool)
207-
208201
// ListActions returns a list of Actions that pass the filterFn requirements.
209202
// The indexOffset and maxNum params can be used to control the number of
210203
// actions returned. The return values are the list of actions, the last index
211204
// and the total count (iff query.CountTotal is set).
212-
func (db *BoltDB) ListActions(filterFn ListActionsFilterFn,
213-
query *ListActionsQuery) ([]*Action, uint64, uint64, error) {
205+
// ListActions returns a list of Actions. The query IndexOffset and MaxNum
206+
// params can be used to control the number of actions returned.
207+
// ListActionOptions may be used to filter on specific Action values. The return
208+
// values are the list of actions, the last index and the total count (iff
209+
// query.CountTotal is set).
210+
func (db *BoltDB) ListActions(ctx context.Context, query *ListActionsQuery,
211+
options ...ListActionOption) ([]*Action, uint64, uint64, error) {
212+
213+
opts := newListActionOptions()
214+
for _, o := range options {
215+
o(opts)
216+
}
217+
218+
filterFn := func(a *Action, reversed bool) (bool, bool) {
219+
timeStamp := a.AttemptedAt
220+
if !opts.endTime.IsZero() {
221+
// If actions are being considered in order and the
222+
// timestamp of this action exceeds the given end
223+
// timestamp, then there is no need to continue
224+
// traversing.
225+
if !reversed && timeStamp.After(opts.endTime) {
226+
return false, false
227+
}
228+
229+
// If the actions are in reverse order and the timestamp
230+
// comes after the end timestamp, then the actions is
231+
// not included but the search can continue.
232+
if reversed && timeStamp.After(opts.endTime) {
233+
return false, true
234+
}
235+
}
236+
237+
if !opts.startTime.IsZero() {
238+
// If actions are being considered in order and the
239+
// timestamp of this action comes before the given start
240+
// timestamp, then the action is not included but the
241+
// search can continue.
242+
if !reversed && timeStamp.Before(opts.startTime) {
243+
return false, true
244+
}
245+
246+
// If the actions are in reverse order and the timestamp
247+
// comes before the start timestamp, then there is no
248+
// need to continue traversing.
249+
if reversed && timeStamp.Before(opts.startTime) {
250+
return false, false
251+
}
252+
}
253+
254+
if opts.featureName != "" && a.FeatureName != opts.featureName {
255+
return false, true
256+
}
257+
258+
if opts.actorName != "" && a.ActorName != opts.actorName {
259+
return false, true
260+
}
261+
262+
if opts.methodName != "" && a.RPCMethod != opts.methodName {
263+
return false, true
264+
}
265+
266+
if opts.state != ActionStateUnknown && a.State != opts.state {
267+
return false, true
268+
}
269+
270+
return true, true
271+
}
272+
273+
if opts.sessionID != session.EmptyID {
274+
return db.listSessionActions(
275+
opts.sessionID, filterFn, query,
276+
)
277+
}
278+
if opts.groupID != session.EmptyID {
279+
actions, err := db.listGroupActions(ctx, opts.groupID, filterFn)
280+
if err != nil {
281+
return nil, 0, 0, err
282+
}
283+
284+
return actions, 0, uint64(len(actions)), nil
285+
}
214286

215287
var (
216288
actions []*Action
@@ -222,30 +294,24 @@ func (db *BoltDB) ListActions(filterFn ListActionsFilterFn,
222294
if err != nil {
223295
return err
224296
}
225-
226297
actionsBucket := mainActionsBucket.Bucket(actionsKey)
227298
if actionsBucket == nil {
228299
return ErrNoSuchKeyFound
229300
}
230-
231301
actionsIndexBucket := mainActionsBucket.Bucket(actionsIndex)
232302
if actionsIndexBucket == nil {
233303
return ErrNoSuchKeyFound
234304
}
235-
236305
readAction := func(index, locatorBytes []byte) (*Action,
237306
error) {
238-
239307
locator, err := deserializeActionLocator(
240308
bytes.NewReader(locatorBytes),
241309
)
242310
if err != nil {
243311
return nil, err
244312
}
245-
246313
return getAction(actionsBucket, locator)
247314
}
248-
249315
actions, lastIndex, totalCount, err = paginateActions(
250316
query, actionsIndexBucket.Cursor(), readAction,
251317
filterFn,
@@ -255,14 +321,20 @@ func (db *BoltDB) ListActions(filterFn ListActionsFilterFn,
255321
if err != nil {
256322
return nil, 0, 0, err
257323
}
258-
259324
return actions, lastIndex, totalCount, nil
260325
}
261326

262-
// ListSessionActions returns a list of the given session's Actions that pass
327+
// listActionsFilterFn defines a function that can be used to determine if an
328+
// action should be included in a set of results or not. The reversed parameter
329+
// indicates if the actions are being traversed in reverse order or not.
330+
// The first return boolean indicates if the action should be included or not
331+
// and the second one indicates if the iteration should be stopped or not.
332+
type listActionsFilterFn func(a *Action, reversed bool) (bool, bool)
333+
334+
// listSessionActions returns a list of the given session's Actions that pass
263335
// the filterFn requirements.
264-
func (db *BoltDB) ListSessionActions(sessionID session.ID,
265-
filterFn ListActionsFilterFn, query *ListActionsQuery) ([]*Action,
336+
func (db *BoltDB) listSessionActions(sessionID session.ID,
337+
filterFn listActionsFilterFn, query *ListActionsQuery) ([]*Action,
266338
uint64, uint64, error) {
267339

268340
var (
@@ -303,12 +375,12 @@ func (db *BoltDB) ListSessionActions(sessionID session.ID,
303375
return actions, lastIndex, totalCount, nil
304376
}
305377

306-
// ListGroupActions returns a list of the given session group's Actions that
378+
// listGroupActions returns a list of the given session group's Actions that
307379
// pass the filterFn requirements.
308380
//
309381
// TODO: update to allow for pagination.
310-
func (db *BoltDB) ListGroupActions(ctx context.Context, groupID session.ID,
311-
filterFn ListActionsFilterFn) ([]*Action, error) {
382+
func (db *BoltDB) listGroupActions(ctx context.Context, groupID session.ID,
383+
filterFn listActionsFilterFn) ([]*Action, error) {
312384

313385
if filterFn == nil {
314386
filterFn = func(a *Action, reversed bool) (bool, bool) {

0 commit comments

Comments
 (0)