From 4916245bf237f1cf427468fc78ca7f0f674c0234 Mon Sep 17 00:00:00 2001 From: jkoberg Date: Mon, 24 Jun 2024 14:55:29 +0200 Subject: [PATCH] feat(activitylog): add a mutex to the store Signed-off-by: jkoberg --- .../6.0.0_2024-06-19/activity-service.md | 1 - changelog/unreleased/activity-api.md | 5 ++ services/activitylog/pkg/service/service.go | 50 ++++++++++++------- 3 files changed, 38 insertions(+), 18 deletions(-) create mode 100644 changelog/unreleased/activity-api.md diff --git a/changelog/6.0.0_2024-06-19/activity-service.md b/changelog/6.0.0_2024-06-19/activity-service.md index 8f82f56fe79..1058280a061 100644 --- a/changelog/6.0.0_2024-06-19/activity-service.md +++ b/changelog/6.0.0_2024-06-19/activity-service.md @@ -2,5 +2,4 @@ Enhancement: Activitylog Service Adds a new service `activitylog` which stores events (activities) per resource. This data can be retrieved by clients to show item activities -https://github.com/owncloud/ocis/pull/9360 https://github.com/owncloud/ocis/pull/9327 diff --git a/changelog/unreleased/activity-api.md b/changelog/unreleased/activity-api.md new file mode 100644 index 00000000000..fd39c2be72b --- /dev/null +++ b/changelog/unreleased/activity-api.md @@ -0,0 +1,5 @@ +Enhancement: Activitylog API + +Adds an api to the `activitylog` service which allows retrieving data by clients to show item activities + +https://github.com/owncloud/ocis/pull/9361 diff --git a/services/activitylog/pkg/service/service.go b/services/activitylog/pkg/service/service.go index 7b4cfd3a459..2653bd434ba 100644 --- a/services/activitylog/pkg/service/service.go +++ b/services/activitylog/pkg/service/service.go @@ -6,6 +6,7 @@ import ( "fmt" "path/filepath" "reflect" + "sync" "time" gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1" @@ -40,6 +41,7 @@ type ActivitylogService struct { mux *chi.Mux evHistory ehsvc.EventHistoryService valService settingssvc.ValueService + lock sync.RWMutex registeredEvents map[string]events.Unmarshaller } @@ -73,6 +75,7 @@ func New(opts ...Option) (*ActivitylogService, error) { mux: o.Mux, evHistory: o.HistoryClient, valService: o.ValueClient, + lock: sync.RWMutex{}, registeredEvents: make(map[string]events.Unmarshaller), } @@ -184,28 +187,18 @@ func (a *ActivitylogService) AddSpaceActivity(spaceID *provider.StorageSpaceId, // Activities returns the activities for the given resource func (a *ActivitylogService) Activities(rid *provider.ResourceId) ([]RawActivity, error) { - resourceID := storagespace.FormatResourceID(*rid) - - records, err := a.store.Read(resourceID) - if err != nil && err != microstore.ErrNotFound { - return nil, fmt.Errorf("could not read activities: %w", err) - } - - if len(records) == 0 { - return []RawActivity{}, nil - } + a.lock.RLock() + defer a.lock.RUnlock() - var activities []RawActivity - if err := json.Unmarshal(records[0].Value, &activities); err != nil { - return nil, fmt.Errorf("could not unmarshal activities: %w", err) - } - - return activities, nil + return a.activities(rid) } // RemoveActivities removes the activities from the given resource func (a *ActivitylogService) RemoveActivities(rid *provider.ResourceId, toDelete map[string]struct{}) error { - curActivities, err := a.Activities(rid) + a.lock.Lock() + defer a.lock.Unlock() + + curActivities, err := a.activities(rid) if err != nil { return err } @@ -228,6 +221,26 @@ func (a *ActivitylogService) RemoveActivities(rid *provider.ResourceId, toDelete }) } +func (a *ActivitylogService) activities(rid *provider.ResourceId) ([]RawActivity, error) { + resourceID := storagespace.FormatResourceID(*rid) + + records, err := a.store.Read(resourceID) + if err != nil && err != microstore.ErrNotFound { + return nil, fmt.Errorf("could not read activities: %w", err) + } + + if len(records) == 0 { + return []RawActivity{}, nil + } + + var activities []RawActivity + if err := json.Unmarshal(records[0].Value, &activities); err != nil { + return nil, fmt.Errorf("could not unmarshal activities: %w", err) + } + + return activities, nil +} + // note: getResource is abstracted to allow unit testing, in general this will just be utils.GetResource func (a *ActivitylogService) addActivity(initRef *provider.Reference, eventID string, timestamp time.Time, getResource func(*provider.Reference) (*provider.ResourceInfo, error)) error { var ( @@ -256,6 +269,9 @@ func (a *ActivitylogService) addActivity(initRef *provider.Reference, eventID st } func (a *ActivitylogService) storeActivity(resourceID string, eventID string, depth int, timestamp time.Time) error { + a.lock.Lock() + defer a.lock.Unlock() + records, err := a.store.Read(resourceID) if err != nil && err != microstore.ErrNotFound { return err