From 487d8420049c091538bfc622544cd12cafa3f1f8 Mon Sep 17 00:00:00 2001 From: geolffreym Date: Sat, 11 Jun 2022 09:46:41 -0600 Subject: [PATCH] synchronization/read-write-lock: peer connection router example implementation --- synchronization/read_write_lock.md | 111 +++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) create mode 100644 synchronization/read_write_lock.md diff --git a/synchronization/read_write_lock.md b/synchronization/read_write_lock.md new file mode 100644 index 0000000..644d383 --- /dev/null +++ b/synchronization/read_write_lock.md @@ -0,0 +1,111 @@ +# Read/Write Lock Pattern +Allows parallel read access, but only exclusive access on write operations to a resource + +## Implementation + +```go +package router + +import ( + "sync" +) + +type Socket string +type Peer interface { + socket Socket + connection net.Conn +} + +func (p *Peer) Socket() Socket { + return p.socket +} + +// Router hash table to associate Socket with Peers. +// Unstructured mesh architecture +// eg. {127.0.0.1:4000: Peer} +type Router struct { + sync.RWMutex + table map[Socket]Peer +} + + +// Return connection interface based on socket +func (r *Router) Query(socket Socket) *Peer { + // Mutex for reading topics. + // Do not write while topics are read. + // Write Lock can’t be acquired until all Read Locks are released. + r.RWMutex.RLock() + defer r.RWMutex.RUnlock() + + if peer, ok := r.table[socket]; ok { + return peer + } + + return nil +} + +// Add create new socket connection association +func (r *Router) Add(peer *Peer) { + // Lock write table while add operation + // A blocked Lock call excludes new readers from acquiring the lock. + r.RWMutex.Lock() + r.table[peer.Socket()] = peer + r.RWMutex.Unlock() +} + +// Delete removes a connection from router +func (r *Router) Delete(peer *Peer) { + // Lock write table while delete operation + // A blocked Lock call excludes new readers from acquiring the lock. + r.RWMutex.Lock() + delete(r.table, peer.Socket()) + r.RWMutex.Unlock() +} +``` + +## Usage +### Syncronize routing peers + +```go + +// New router +router:= &Router{ + table: make(map[Socket]Peer) +} + +// !Important: +// 1 - Write Lock can’t be acquired until all Read Locks are released. +// 2 - A blocked Lock call excludes new readers from acquiring the lock. + +// Writing operation +go func(r *Router){ + for { + // this will be running waiting for new connections + /// .. some code here + conn, err := listener.Accept() + // eg. 192.168.1.1:8080 + remote := connection.RemoteAddr().String() + socket := Socket(address) + // New peer + peer := &Peer{ + socket: socket, + connection: conn + } + // Here we need a write lock to avoid race condition + r.Add(peer) + } +}(router) + +// Reading operation +go func(r *Router){ + // ...some logic here + // reading operation 1 + connection := r.Query("192.168.1.1:8080") + //... more code here + // reading operation 2 + otherQuery:= r.Query("192.168.1.1:8081") + // read locks are like counters.. + // until counter = 0 Write can be acquired +}(router) + +``` \ No newline at end of file