diff --git a/src/router/functionServiceMap.go b/src/router/functionServiceMap.go new file mode 100644 index 00000000..98997ab9 --- /dev/null +++ b/src/router/functionServiceMap.go @@ -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 } +} diff --git a/src/router/functionServiceMap_test.go b/src/router/functionServiceMap_test.go new file mode 100644 index 00000000..b5c9897b --- /dev/null +++ b/src/router/functionServiceMap_test.go @@ -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") + } +}