Skip to content

Commit

Permalink
Rename context find (#58)
Browse files Browse the repository at this point in the history
  • Loading branch information
dylanratcliffe authored Dec 13, 2022
1 parent e6a6feb commit 2c8e58d
Show file tree
Hide file tree
Showing 19 changed files with 546 additions and 561 deletions.
20 changes: 10 additions & 10 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Look at the tests for some simple examples of starting and running an engine, or

Triggers allow source developers to have their source be triggered by the discover of other items on the NATS network. This allows for a pattern where a source is triggered by a relevant resource being discovered by another query, rather than by being queried directly. This can be used to write secondary sources that fire automatically e.g.

> When a package with the name "nginx" is found in any context, the source should be triggered to try to find the config file for nginx in this context, parse it, and return more detailed information.
> When a package with the name "nginx" is found in any scope, the source should be triggered to try to find the config file for nginx in this scope, parse it, and return more detailed information.
The anatomy of a trigger is as follows:

Expand All @@ -39,8 +39,8 @@ var trigger = Trigger{
// function should return the request that should be forwarded to the
// engine that the trigger is registered with
RequestGenerator: func(in *sdp.Item) (*sdp.ItemRequest, error) {
if in.GetContext() != "something" {
return nil, errors.New("only 'something' context supported")
if in.GetScope() != "something" {
return nil, errors.New("only 'something' scope supported")
} else {
return &sdp.ItemRequest{
Type: "dog",
Expand All @@ -63,17 +63,17 @@ This source returns information about other sources as SDP items. Can be used to
Methods:

* [x] `Get()`: Returns sources by their descriptive name
* [x] `Find()`
* [x] `List()`
* [ ] `Search()`

### `overmind-context`
### `overmind-scope`

Returns available contexts as SDP items. This is intended to be used to improve UX in the GUI since users will be able to see what contexts are available.
Returns available scopes as SDP items. This is intended to be used to improve UX in the GUI since users will be able to see what scopes are available.

Methods:

* [x] `Get()`: Returns contexts by their name
* [x] `Find()`
* [x] `Get()`: Returns scopes by their name
* [x] `List()`
* [x] `Search()`: Search by any string. Intended to be used by autocomplete in the GUI and therefore places extra weight on prefixes however will also perform free-text and fuzzy matching too

### `overmind-type`
Expand All @@ -82,8 +82,8 @@ Returns available types as SDP items. This is intended to be used to improve UX

Methods:

* [x] `Get()`: Returns contexts by their name
* [x] `Find()`
* [x] `Get()`: Returns scopes by their name
* [x] `List()`
* [x] `Search()`: Search by any string. Intended to be used by autocomplete in the GUI and therefore places extra weight on prefixes however will also perform free-text and fuzzy matching too


Expand Down
30 changes: 15 additions & 15 deletions engine.go
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,8 @@ type Engine struct {
triggers []*Trigger
triggersMutex sync.RWMutex

// GetFindMutex used for locking
gfm GetFindMutex
// GetListMutex used for locking
gfm GetListMutex

// trackedRequests is used for storing requests that have a UUID so they can
// be cancelled if required
Expand Down Expand Up @@ -164,7 +164,7 @@ func (e *Engine) AddSources(sources ...Source) {
}

// AddTriggers Adds a trigger to this engine. Triggers cause the engine to
// listen for items from other contexts and will fire a custom ItemRequest if
// listen for items from other scopes and will fire a custom ItemRequest if
// they match
func (e *Engine) AddTriggers(triggers ...Trigger) {
e.triggersMutex.Lock()
Expand Down Expand Up @@ -323,7 +323,7 @@ func (e *Engine) connect() error {
}

// Loop over all sources and work out what subscriptions we need to make
// depending on what contexts they support. These context names are then
// depending on what scopes they support. These scope names are then
// stored in a map for de-duplication before being subscribed to
subscriptionMap := make(map[string]bool)

Expand All @@ -334,23 +334,23 @@ func (e *Engine) connect() error {
var wildcardExists bool

for _, src := range e.Sources() {
for _, itemContext := range src.Contexts() {
if itemContext == sdp.WILDCARD {
for _, itemScope := range src.Scopes() {
if itemScope == sdp.WILDCARD {
wildcardExists = true
} else {
subscriptionMap[itemContext] = true
subscriptionMap[itemScope] = true
}
}
}

// Now actually create the required subscriptions
if wildcardExists {
e.subscribe("request.context.>", e.ItemRequestHandler)
e.subscribe("cancel.context.>", e.CancelHandler)
e.subscribe("request.scope.>", e.ItemRequestHandler)
e.subscribe("cancel.scope.>", e.CancelHandler)
} else {
for suffix := range subscriptionMap {
e.subscribe(fmt.Sprintf("request.context.%v", suffix), e.ItemRequestHandler)
e.subscribe(fmt.Sprintf("cancel.context.%v", suffix), e.CancelHandler)
e.subscribe(fmt.Sprintf("request.scope.%v", suffix), e.ItemRequestHandler)
e.subscribe(fmt.Sprintf("cancel.scope.%v", suffix), e.CancelHandler)
}
}

Expand Down Expand Up @@ -409,20 +409,20 @@ func (e *Engine) Start() error {
e.SetupMaxRequestTimeout()

var typeSource Source
var contextSource Source
var scopeSource Source
var sourceSource Source
var ms *MetaSource
var err error

// Add meta-sources so that we can respond to requests for `overmind-type`,
// `overmind-context` and `overmind-source` resources
// `overmind-scope` and `overmind-source` resources
typeSource, err = NewMetaSource(e, Type)

if err != nil {
return err
}

contextSource, err = NewMetaSource(e, Context)
scopeSource, err = NewMetaSource(e, Scope)

if err != nil {
return err
Expand All @@ -438,7 +438,7 @@ func (e *Engine) Start() error {
MetaSource: *ms,
}

e.AddSources(typeSource, contextSource, sourceSource)
e.AddSources(typeSource, scopeSource, sourceSource)

// Start purging cache
e.cache.StartPurger()
Expand Down
34 changes: 17 additions & 17 deletions engine_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -18,14 +18,14 @@ import (

func TestDeleteItemRequest(t *testing.T) {
one := &sdp.ItemRequest{
Context: "one",
Method: sdp.RequestMethod_FIND,
Query: "",
Scope: "one",
Method: sdp.RequestMethod_LIST,
Query: "",
}
two := &sdp.ItemRequest{
Context: "two",
Method: sdp.RequestMethod_SEARCH,
Query: "2",
Scope: "two",
Method: sdp.RequestMethod_SEARCH,
Query: "2",
}
irs := []*sdp.ItemRequest{
one,
Expand Down Expand Up @@ -53,7 +53,7 @@ func TestTrackRequest(t *testing.T) {
Engine: &e,
Request: &sdp.ItemRequest{
Type: "person",
Method: sdp.RequestMethod_FIND,
Method: sdp.RequestMethod_LIST,
LinkDepth: 10,
UUID: u[:],
},
Expand Down Expand Up @@ -169,7 +169,7 @@ func TestNats(t *testing.T) {
e.AddSources(
&src,
&TestSource{
ReturnContexts: []string{
ReturnScopes: []string{
sdp.WILDCARD,
},
},
Expand Down Expand Up @@ -198,7 +198,7 @@ func TestNats(t *testing.T) {
Method: sdp.RequestMethod_GET,
Query: "basic",
LinkDepth: 0,
Context: "test",
Scope: "test",
ResponseSubject: NewResponseSubject(),
ItemSubject: NewItemSubject(),
})
Expand All @@ -225,7 +225,7 @@ func TestNats(t *testing.T) {
Method: sdp.RequestMethod_GET,
Query: "deeplink",
LinkDepth: 10,
Context: "test",
Scope: "test",
ResponseSubject: NewResponseSubject(),
ItemSubject: NewItemSubject(),
})
Expand Down Expand Up @@ -268,9 +268,9 @@ func TestNatsCancel(t *testing.T) {
}

src := SpeedTestSource{
QueryDelay: 250 * time.Millisecond,
ReturnType: "person",
ReturnContexts: []string{"test"},
QueryDelay: 250 * time.Millisecond,
ReturnType: "person",
ReturnScopes: []string{"test"},
}

e.AddSources(&src)
Expand All @@ -292,7 +292,7 @@ func TestNatsCancel(t *testing.T) {
Method: sdp.RequestMethod_GET,
Query: "foo",
LinkDepth: 100,
Context: "*",
Scope: "*",
ResponseSubject: nats.NewInbox(),
ItemSubject: "items.bin",
UUID: u[:],
Expand Down Expand Up @@ -555,7 +555,7 @@ func TestNatsAuth(t *testing.T) {
e.AddSources(
&src,
&TestSource{
ReturnContexts: []string{
ReturnScopes: []string{
sdp.WILDCARD,
},
},
Expand Down Expand Up @@ -584,7 +584,7 @@ func TestNatsAuth(t *testing.T) {
Method: sdp.RequestMethod_GET,
Query: "basic",
LinkDepth: 0,
Context: "test",
Scope: "test",
ResponseSubject: NewResponseSubject(),
ItemSubject: NewItemSubject(),
}).Execute(e.natsConnection)
Expand All @@ -609,7 +609,7 @@ func TestNatsAuth(t *testing.T) {
Method: sdp.RequestMethod_GET,
Query: "deeplink",
LinkDepth: 10,
Context: "test",
Scope: "test",
ResponseSubject: NewResponseSubject(),
ItemSubject: NewItemSubject(),
}).Execute(e.natsConnection)
Expand Down
52 changes: 26 additions & 26 deletions getfindmutex.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,53 +5,53 @@ import (
"sync"
)

// GetFindMutex A modified version of a RWMutex. Many get locks can be held but
// only one Find lock. A waiting Find lock (even if it hasn't been locked, just
// GetListMutex A modified version of a RWMutex. Many get locks can be held but
// only one List lock. A waiting List lock (even if it hasn't been locked, just
// if someone is waiting) blocks all other get locks until it unlocks.
//
// The intended usage of this is that it will allow a source which is trying to
// process many requests at once, to process a FIND request before any GET
// requests, since it's likely that once FIND has been run, subsequent GET
// process many requests at once, to process a LIST request before any GET
// requests, since it's likely that once LIST has been run, subsequent GET
// requests will be able to be served from cache
type GetFindMutex struct {
type GetListMutex struct {
mutexMap map[string]*sync.RWMutex
mapLock sync.Mutex
}

// GetLock Gets a lock that can be held by an unlimited number of goroutines,
// these locks are only blocked by FindLocks. A type and context must be
// provided since a Get in one type (or context) should not be blocked by a Find
// these locks are only blocked by ListLocks. A type and scope must be
// provided since a Get in one type (or scope) should not be blocked by a List
// in another
func (g *GetFindMutex) GetLock(itemContext string, typ string) {
g.mutexFor(itemContext, typ).RLock()
func (g *GetListMutex) GetLock(scope string, typ string) {
g.mutexFor(scope, typ).RLock()
}

// GetUnlock Unlocks the GetLock. This must be called once for each GetLock
// otherwise it will be impossible to ever obtain a FindLock
func (g *GetFindMutex) GetUnlock(itemContext string, typ string) {
g.mutexFor(itemContext, typ).RUnlock()
// otherwise it will be impossible to ever obtain a ListLock
func (g *GetListMutex) GetUnlock(scope string, typ string) {
g.mutexFor(scope, typ).RUnlock()
}

// FindLock An exclusive lock. Ensure that all GetLocks have been unlocked and
// stops any more from being obtained. Provide a type and context to ensure that
// the lock is only help for that type and context combination rather than
// ListLock An exclusive lock. Ensure that all GetLocks have been unlocked and
// stops any more from being obtained. Provide a type and scope to ensure that
// the lock is only help for that type and scope combination rather than
// locking the whole engine
func (g *GetFindMutex) FindLock(itemContext string, typ string) {
g.mutexFor(itemContext, typ).Lock()
func (g *GetListMutex) ListLock(scope string, typ string) {
g.mutexFor(scope, typ).Lock()
}

// FindUnlock Unlocks a FindLock
func (g *GetFindMutex) FindUnlock(itemContext string, typ string) {
g.mutexFor(itemContext, typ).Unlock()
// ListUnlock Unlocks a ListLock
func (g *GetListMutex) ListUnlock(scope string, typ string) {
g.mutexFor(scope, typ).Unlock()
}

// mutexFor Returns the relevant RWMutex for a given context and type, creating
// mutexFor Returns the relevant RWMutex for a given scope and type, creating
// and storing a new one if needed
func (g *GetFindMutex) mutexFor(itemContext string, typ string) *sync.RWMutex {
func (g *GetListMutex) mutexFor(scope string, typ string) *sync.RWMutex {
var mutex *sync.RWMutex
var ok bool

keyName := g.keyName(itemContext, typ)
keyName := g.keyName(scope, typ)

g.mapLock.Lock()
defer g.mapLock.Unlock()
Expand All @@ -73,8 +73,8 @@ func (g *GetFindMutex) mutexFor(itemContext string, typ string) *sync.RWMutex {
return mutex
}

// keyName Returns the name of the key for a given context and type combo for
// keyName Returns the name of the key for a given scope and type combo for
// use with the mutexMap
func (g *GetFindMutex) keyName(itemContext string, typ string) string {
return fmt.Sprintf("%v.%v", itemContext, typ)
func (g *GetListMutex) keyName(scope string, typ string) string {
return fmt.Sprintf("%v.%v", scope, typ)
}
Loading

0 comments on commit 2c8e58d

Please sign in to comment.