Last active
August 29, 2015 14:15
-
-
Save adityagodbole/2e2786b8b8b66e27f165 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"errors" | |
"os" | |
"fmt" | |
"reflect" | |
"strconv" | |
) | |
// The interface of the type which embeds the original struct | |
// The way to interact with the new | |
type Agent interface { | |
Send(string, ...interface{}) (interface{}, error) | |
Stop() | |
Raw() interface{} | |
} | |
// Our default implementation | |
type atomicData struct { | |
d interface{} | |
com_ch chan msg | |
methods map[string]*reflect.Method | |
} | |
// Internal type for the command message | |
type msg struct { | |
Com string | |
Params []interface{} | |
RetCh chan resp | |
} | |
// Internal type for the response | |
type resp struct { | |
Res interface{} | |
Ok bool | |
} | |
func (a *atomicData) Raw() interface{} { | |
return a.d | |
} | |
func (a *atomicData) Stop() { | |
a.com_ch <- msg{Com: "AgentStop"} | |
} | |
func (a *atomicData) Send(com string, p ...interface{}) (interface{}, error) { | |
ch := make(chan resp) | |
a.com_ch <- msg{Com: com, RetCh: ch, Params: p} | |
res := <-ch | |
close(ch) | |
if res.Ok { | |
return res.Res, nil | |
} | |
return nil, errors.New("No response") | |
} | |
func (a *atomicData) init_chan() { | |
a.com_ch = make(chan msg) | |
} | |
// Memoised (per struct) method retrieval | |
func (a *atomicData) getMethod(name string) (*reflect.Method, bool) { | |
if a.methods[name] != nil { | |
return a.methods[name], true | |
} | |
blobType := reflect.TypeOf(a.d) | |
method, found := blobType.MethodByName(name) | |
a.methods[name] = &method | |
return &method, found | |
} | |
func call_op(a *atomicData , fname string, params []interface{}) (resp, error) { | |
d := a.d | |
method, found := a.getMethod(fname) | |
if !found { | |
return resp{}, errors.New(fmt.Sprintf("Method %d not found", fname)) | |
} | |
fvalue := method.Func | |
if fvalue.Kind() != reflect.Func { | |
return resp{}, errors.New("Handler is not a function type") | |
} | |
methodType := method.Type | |
if methodType.NumIn() != len(params)+1 { | |
msg := fmt.Sprintf("Handler parameter arity error (%d instead of %d)", len(params), | |
methodType.NumIn()) | |
return resp{}, errors.New(msg) | |
} | |
args := make([]reflect.Value, 8) | |
args[0] = reflect.ValueOf(d) | |
for i := 1; i < methodType.NumIn(); i++ { | |
arg := params[i-1] | |
args[i] = reflect.ValueOf(arg) | |
} | |
// call the function with the params | |
res := fvalue.Call(args[0:methodType.NumIn()]) | |
resp := resp{} | |
if methodType.NumOut() > 0 { | |
resp.Ok = true | |
resp.Res = res[0].Interface() | |
} | |
return resp, nil | |
} | |
func Go(d interface{}) Agent { | |
a := &atomicData{d: d} | |
a.init_chan() | |
a.methods = make(map[string]*reflect.Method) | |
go func() { | |
for msg := range a.com_ch { | |
if msg.Com == "AgentStop" { | |
return | |
} | |
res, err := call_op(a, msg.Com, msg.Params) | |
if err != nil { | |
fmt.Println(err.Error()) | |
} | |
if msg.RetCh != nil { | |
msg.RetCh <- res | |
} | |
} | |
}() | |
return a | |
} | |
/////////////////////////////////////////////////////////////////// | |
// This is the code a user of the Agent library would have to write | |
/////////////////////////////////////////////////////////////////// | |
type myStruct struct { | |
val int | |
at Agent | |
} | |
func (a *myStruct) Inc(n int) int { | |
a.val += n | |
return a.val | |
} | |
func (a myStruct) Val() int { | |
return a.val | |
} | |
func New(val int) Agent { | |
a := &myStruct{val: val} | |
return Go(a) | |
} | |
func main() { | |
arg, _ := strconv.ParseInt(os.Args[1], 10, 0) | |
n_mut := int(arg) | |
i := New(10) | |
defer i.Stop() | |
ch := make(chan bool) | |
mutator := func() { | |
i.Send("Inc", 1) | |
ch <- true | |
} | |
for i := 0; i < n_mut; i++ { | |
go mutator() | |
} | |
rcount := 0 | |
for _ = range ch { | |
rcount++ | |
if rcount >= n_mut { | |
fmt.Printf("%d", i.Raw().(*myStruct).Val()) | |
break | |
} | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package main | |
import ( | |
"fmt" | |
"os" | |
"strconv" | |
) | |
type Blob interface { | |
IsBlob() | |
} | |
type AtomicData interface { | |
Send(string, interface{}, bool) interface{} | |
} | |
type atomicData struct { | |
d Blob | |
com_ch chan Msg | |
ops map[string]Op | |
} | |
type Op func(Blob, interface{}) interface{} | |
type Msg struct { | |
Com string | |
Params interface{} | |
RetCh chan interface{} | |
} | |
func (a *atomicData) Send(com string, p interface{}, hasResponse bool) interface{} { | |
var ch chan interface{} | |
if hasResponse { | |
ch = make(chan interface{}) | |
} else { | |
ch = nil | |
} | |
a.com_ch <- Msg{Com: com, RetCh: ch, Params: p} | |
var res interface{} | |
if hasResponse { | |
res = <-ch | |
close(ch) | |
} | |
return res | |
} | |
func (a *atomicData) init_chan() { | |
a.com_ch = make(chan Msg) | |
} | |
func Go(d Blob, ops map[string]Op) AtomicData { | |
a := &atomicData{d: d} | |
a.init_chan() | |
go func() { | |
for msg := range a.com_ch { | |
if msg.Com == "AgentStop" { | |
return | |
} | |
fun := ops[msg.Com] | |
res := fun(a.d, msg.Params) | |
if msg.RetCh != nil && res != nil { | |
msg.RetCh <- res | |
} | |
} | |
}() | |
return a | |
} | |
/////////////////////////////////////////////////////////////////// | |
// This is the code a user of the Agent library would have to write | |
/////////////////////////////////////////////////////////////////// | |
type myStruct struct { | |
val int | |
at AtomicData | |
} | |
func (b *myStruct) IsBlob() {} | |
var ops = map[string]Op{ | |
"inc": func(a Blob, params interface{}) interface{} { | |
var data int | |
if params != nil { | |
data = params.(int) | |
} | |
val := a.(*myStruct) | |
return val.inc(data) | |
}, | |
} | |
func (a *myStruct) inc(n int) int { | |
a.val += n | |
return a.val | |
} | |
func (a myStruct) Val() int { | |
return a.val | |
} | |
func New(val int) *myStruct { | |
a := &myStruct{val: val} | |
a.at = Go(a, ops) | |
return a | |
} | |
func (a *myStruct) Delete() { | |
a.at.Send("AgentStop", nil, false) | |
} | |
func (a *myStruct) Inc(n int) int { | |
res := a.at.Send("inc", n, true) | |
return res.(int) | |
} | |
func main() { | |
arg, _ := strconv.ParseInt(os.Args[1], 10, 0) | |
n_mut := int(arg) | |
i := New(10) | |
defer i.Delete() | |
ch := make(chan bool) | |
mutator := func() { | |
i.Inc(1) | |
ch <- true | |
} | |
for i := 0; i < n_mut; i++ { | |
go mutator() | |
} | |
rcount := 0 | |
for _ = range ch { | |
rcount++ | |
if rcount >= n_mut { | |
fmt.Printf("%d", i.Val()) | |
break | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment