Function (name, uid) -> service URL map
Concurrency-safe mapping from a function's (name, uid) identifier to a URL. This will be used to look up the service URL associated with a given function.
This commit is contained in:
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
Copyright 2016 The Fission Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
"errors"
|
||||
"log"
|
||||
)
|
||||
|
||||
type requestType int
|
||||
const (
|
||||
LOOKUP requestType = iota // lookup the map
|
||||
ASSIGN // assign function
|
||||
NEXT_GEN // increment current generation
|
||||
SWEEP // delete all but the current generation
|
||||
)
|
||||
|
||||
type functionServiceMapResponse struct {
|
||||
serviceUrl string
|
||||
error
|
||||
}
|
||||
type functionServiceMapRequest struct {
|
||||
function
|
||||
serviceUrl string
|
||||
requestType
|
||||
responseChannel chan<- functionServiceMapResponse
|
||||
}
|
||||
type functionServiceMapEntry struct {
|
||||
serviceUrl string
|
||||
generation uint64
|
||||
}
|
||||
|
||||
type functionServiceMap struct {
|
||||
// map (funcname, uid) -> url
|
||||
svc map[function]functionServiceMapEntry
|
||||
currentGeneration uint64
|
||||
requestChannel chan *functionServiceMapRequest
|
||||
}
|
||||
|
||||
func makeFunctionServiceMap() (*functionServiceMap) {
|
||||
fmap := &functionServiceMap{}
|
||||
fmap.requestChannel = make(chan *functionServiceMapRequest)
|
||||
fmap.svc = make(map[function]functionServiceMapEntry)
|
||||
go fmap.functionServiceMapWork()
|
||||
return fmap
|
||||
}
|
||||
|
||||
func (fmap *functionServiceMap) functionServiceMapWork() {
|
||||
for {
|
||||
req := <- fmap.requestChannel
|
||||
switch req.requestType {
|
||||
case LOOKUP:
|
||||
e, present := fmap.svc[req.function]
|
||||
if present {
|
||||
req.responseChannel <- functionServiceMapResponse{ serviceUrl: e.serviceUrl }
|
||||
} else {
|
||||
req.responseChannel <- functionServiceMapResponse{ error: errors.New("not found") }
|
||||
}
|
||||
case ASSIGN:
|
||||
fmap.svc[req.function] =
|
||||
functionServiceMapEntry{ serviceUrl: req.serviceUrl, generation: fmap.currentGeneration }
|
||||
// no response
|
||||
case NEXT_GEN:
|
||||
fmap.currentGeneration++
|
||||
// no response
|
||||
case SWEEP:
|
||||
log.Panic("not implemented")
|
||||
default:
|
||||
log.Panic("bad request")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (fmap *functionServiceMap) lookup(f *function) (string, error) {
|
||||
respChannel := make(chan functionServiceMapResponse)
|
||||
fmap.requestChannel <-
|
||||
&functionServiceMapRequest{ function: *f, requestType: LOOKUP, responseChannel: respChannel }
|
||||
resp := <-respChannel
|
||||
if (resp.error != nil) {
|
||||
return "", resp.error
|
||||
} else {
|
||||
return resp.serviceUrl, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (fmap *functionServiceMap) assign(f *function, serviceUrl string) {
|
||||
fmap.requestChannel <-
|
||||
&functionServiceMapRequest{ function: *f, serviceUrl: serviceUrl, requestType: ASSIGN }
|
||||
}
|
||||
|
||||
func (fmap *functionServiceMap) nextGen() {
|
||||
fmap.requestChannel <-
|
||||
&functionServiceMapRequest{ requestType: NEXT_GEN }
|
||||
}
|
||||
|
||||
func (fmap *functionServiceMap) sweep() {
|
||||
fmap.requestChannel <-
|
||||
&functionServiceMapRequest{ requestType: SWEEP }
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/*
|
||||
Copyright 2016 The Fission Authors.
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
*/
|
||||
|
||||
package router
|
||||
|
||||
import (
|
||||
"testing"
|
||||
)
|
||||
|
||||
func TestFunctionServiceMap(t *testing.T) {
|
||||
m := makeFunctionServiceMap()
|
||||
fn := &function{ name: "foo", uid: "012" }
|
||||
url := "/foo012"
|
||||
|
||||
m.assign(fn, url)
|
||||
|
||||
v, err := m.lookup(fn)
|
||||
if (err != nil) {
|
||||
t.Errorf("Lookup error: %s", err)
|
||||
}
|
||||
if (v != url) {
|
||||
t.Errorf("Expected %s, got %s", url, v)
|
||||
}
|
||||
|
||||
fn.name = "bar"
|
||||
_, err2 := m.lookup(fn)
|
||||
if (err2 == nil) {
|
||||
t.Errorf("No error on missing entry")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user