Skip to content

Commit

Permalink
feat(activitylog): add a mutex to the store
Browse files Browse the repository at this point in the history
Signed-off-by: jkoberg <[email protected]>
  • Loading branch information
kobergj committed Jun 24, 2024
1 parent 76ca53b commit 57a30ec
Show file tree
Hide file tree
Showing 4 changed files with 39 additions and 19 deletions.
1 change: 0 additions & 1 deletion changelog/6.0.0_2024-06-19/activity-service.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
5 changes: 5 additions & 0 deletions changelog/unreleased/activity-api.md
Original file line number Diff line number Diff line change
@@ -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
2 changes: 1 addition & 1 deletion services/activitylog/pkg/config/config.go
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ type Store struct {
Database string `yaml:"database" env:"ACTIVITYLOG_STORE_DATABASE" desc:"The database name the configured store should use." introductionVersion:"pre5.0"`
Table string `yaml:"table" env:"ACTIVITYLOG_STORE_TABLE" desc:"The database table the store should use." introductionVersion:"pre5.0"`
TTL time.Duration `yaml:"ttl" env:"OCIS_PERSISTENT_STORE_TTL;ACTIVITYLOG_STORE_TTL" desc:"Time to live for events in the store. See the Environment Variable Types description for more details." introductionVersion:"pre5.0"`
Size int `yaml:"size" env:"OCIS_PERSISTENT_STORE_SIZE;ACTIVITYLOG_STORE_SIZE" desc:"The maximum quantity of items in the store. Only applies when store type 'ocmem' is configured. Defaults to 512 which is derived from the ocmem package though not exclicitly set as default." introductionVersion:"pre5.0"`
Size int `yaml:"size" env:"OCIS_PERSISTENT_STORE_SIZE;ACTIVITYLOG_STORE_SIZE" desc:"The maximum quantity of items in the store. Only applies when store type 'ocmem' is configured. Defaults to 512 which is derived from the ocmem package though not explicitly set as default." introductionVersion:"pre5.0"`
AuthUsername string `yaml:"username" env:"OCIS_PERSISTENT_STORE_AUTH_USERNAME;ACTIVITYLOG_STORE_AUTH_USERNAME" desc:"The username to authenticate with the store. Only applies when store type 'nats-js-kv' is configured." introductionVersion:"5.0"`
AuthPassword string `yaml:"password" env:"OCIS_PERSISTENT_STORE_AUTH_PASSWORD;ACTIVITYLOG_STORE_AUTH_PASSWORD" desc:"The password to authenticate with the store. Only applies when store type 'nats-js-kv' is configured." introductionVersion:"5.0"`
}
Expand Down
50 changes: 33 additions & 17 deletions services/activitylog/pkg/service/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"path/filepath"
"reflect"
"sync"
"time"

gateway "github.com/cs3org/go-cs3apis/cs3/gateway/v1beta1"
Expand Down Expand Up @@ -40,6 +41,7 @@ type ActivitylogService struct {
mux *chi.Mux
evHistory ehsvc.EventHistoryService
valService settingssvc.ValueService
lock sync.RWMutex

registeredEvents map[string]events.Unmarshaller
}
Expand Down Expand Up @@ -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),
}

Expand Down Expand Up @@ -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
}
Expand All @@ -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 (
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit 57a30ec

Please sign in to comment.