Skip to content
Next Next commit
synchronization/read-write-lock: peer conenction router example imple…
…mentation
  • Loading branch information
geolffreym committed Jun 10, 2022
commit 86986ad8b302b6d14bd9d01e2cd607aeec6e62fc
110 changes: 110 additions & 0 deletions synchronization/read-write-lock.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
# 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/read table while add operation
// A blocked Lock call excludes new readers from acquiring the lock.
r.RWMutex.Lock()
defer r.RWMutex.Unlock()
r.table[peer.Socket()] = peer
}

// Delete removes a connection from router
func (r *Router) Delete(peer *Peer) {
// Lock write/read table while delete operation
// A blocked Lock call excludes new readers from acquiring the lock.
r.RWMutex.Lock()
defer r.RWMutex.Unlock()
delete(r.table, peer.Socket())
}
```

## Usage
### Syncronize routing peers from incoming connections

```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 := router.Query("192.168.1.1:8080")
//... more code here
// reading operation 2
otherQuery:= router.Query("192.168.1.1:8081")
// read locks are like counters.. until counter = 0 Write can be acquired
}(router)

```