mirror of https://github.com/docker/docs.git
Beam in-mem: an in-memory implementation of Beam
This commit is contained in:
parent
2c9e18009f
commit
3725628467
|
|
@ -0,0 +1,89 @@
|
|||
package inmem
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io"
|
||||
"sync"
|
||||
)
|
||||
|
||||
type Handle interface {
|
||||
Send(msg *Message, mode int) (Handle, error)
|
||||
Receive(mode int) (*Message, Handle, error)
|
||||
CloseWrite() error
|
||||
}
|
||||
|
||||
const (
|
||||
R = 1 << (32 - 1 - iota)
|
||||
W
|
||||
)
|
||||
|
||||
type Message struct {
|
||||
Target string
|
||||
Name string
|
||||
Args []string
|
||||
Data string
|
||||
}
|
||||
|
||||
|
||||
func Pipe() (Handle, Handle) {
|
||||
red := make(chan *pipeMessage)
|
||||
black := make(chan *pipeMessage)
|
||||
return &PipeHandle{r: red, w: black}, &PipeHandle{r: black, w: red}
|
||||
}
|
||||
|
||||
type PipeHandle struct {
|
||||
sync.RWMutex
|
||||
r chan *pipeMessage
|
||||
w chan *pipeMessage
|
||||
}
|
||||
|
||||
func (h *PipeHandle) Send(msg *Message, mode int) (Handle, error) {
|
||||
h.RLock()
|
||||
defer h.RUnlock()
|
||||
if h.w == nil {
|
||||
return nil, fmt.Errorf("closed pipe")
|
||||
}
|
||||
var (
|
||||
rh Handle
|
||||
lh Handle
|
||||
)
|
||||
if mode&(R|W) != 0 {
|
||||
rh, lh = Pipe()
|
||||
if mode&W == 0 {
|
||||
lh.CloseWrite()
|
||||
}
|
||||
}
|
||||
h.w <-&pipeMessage{msg, rh}
|
||||
return lh, nil
|
||||
}
|
||||
|
||||
func (h *PipeHandle) Receive(mode int) (*Message, Handle, error) {
|
||||
pmsg, ok := <-h.r
|
||||
if !ok {
|
||||
return nil, nil, io.EOF
|
||||
}
|
||||
var handle Handle
|
||||
if pmsg.handle != nil && mode&W == 0 {
|
||||
pmsg.handle.CloseWrite()
|
||||
}
|
||||
if mode&(R|W) != 0 {
|
||||
handle = pmsg.handle
|
||||
}
|
||||
return pmsg.payload, handle, nil
|
||||
}
|
||||
|
||||
func (h *PipeHandle) CloseWrite() error {
|
||||
h.Lock()
|
||||
defer h.Unlock()
|
||||
if h.w == nil {
|
||||
return fmt.Errorf("already closed")
|
||||
}
|
||||
close(h.w)
|
||||
h.w = nil
|
||||
return nil
|
||||
}
|
||||
|
||||
type pipeMessage struct {
|
||||
payload *Message
|
||||
handle Handle
|
||||
}
|
||||
|
|
@ -0,0 +1,44 @@
|
|||
package inmem
|
||||
|
||||
import (
|
||||
"testing"
|
||||
"time"
|
||||
)
|
||||
|
||||
func TestSimpleSend(t *testing.T) {
|
||||
a, b := Pipe()
|
||||
defer a.CloseWrite()
|
||||
defer b.CloseWrite()
|
||||
onTimeout := time.After(100 * time.Millisecond)
|
||||
onRcv := make(chan bool)
|
||||
go func() {
|
||||
msg, h, err := b.Receive(0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if msg.Data != "hello world" {
|
||||
t.Fatalf("%#v", *msg)
|
||||
}
|
||||
if msg.Name != "print" {
|
||||
t.Fatalf("%#v", *msg)
|
||||
}
|
||||
if len(msg.Args) != 0 {
|
||||
t.Fatalf("%#v", *msg)
|
||||
}
|
||||
if h != nil {
|
||||
t.Fatalf("%#v", h)
|
||||
}
|
||||
close(onRcv)
|
||||
}()
|
||||
h, err := a.Send(&Message{Name:"print", Data: "hello world"}, 0)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if h != nil {
|
||||
t.Fatalf("%#v", h)
|
||||
}
|
||||
select {
|
||||
case <-onTimeout: t.Fatalf("timeout")
|
||||
case <-onRcv:
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue