github.com/graybobo/golang.org-package-offline-cache@v0.0.0-20200626051047-6608995c132f/x/talks/2013/distsys/replread.go (about)

     1  // +build OMIT
     2  
     3  package main
     4  
     5  import (
     6  	"fmt"
     7  	"math"
     8  	"math/rand"
     9  	"sync"
    10  	"time"
    11  )
    12  
    13  const (
    14  	F           = 2
    15  	N           = 5
    16  	ReadQuorum  = F + 1
    17  	WriteQuorum = N - F
    18  )
    19  
    20  var delay = false
    21  
    22  type Server struct {
    23  	mu   sync.Mutex
    24  	data map[string]*Data
    25  }
    26  
    27  type Data struct {
    28  	Key   string
    29  	Value string
    30  	Time  time.Time
    31  }
    32  
    33  func (srv *Server) Delay() {
    34  	if delay == false {
    35  		return
    36  	}
    37  	time.Sleep(time.Duration(math.Abs(rand.NormFloat64()*1e9 + 0.1e9)))
    38  }
    39  
    40  func (srv *Server) Write(req *Data) {
    41  	t0 := time.Now()
    42  	defer func() {
    43  		if delay {
    44  			fmt.Printf("write took %.3f seconds\n", time.Since(t0).Seconds())
    45  		}
    46  	}()
    47  
    48  	srv.mu.Lock()
    49  	defer srv.mu.Unlock()
    50  	srv.Delay()
    51  
    52  	if srv.data == nil {
    53  		srv.data = make(map[string]*Data)
    54  	}
    55  	if d := srv.data[req.Key]; d == nil || d.Time.Before(req.Time) {
    56  		srv.data[req.Key] = req
    57  	}
    58  }
    59  
    60  func (srv *Server) Read(key string) *Data {
    61  	t0 := time.Now()
    62  	defer func() {
    63  		fmt.Printf("read took %.3f seconds\n", time.Since(t0).Seconds())
    64  	}()
    65  
    66  	srv.mu.Lock()
    67  	defer srv.mu.Unlock()
    68  	srv.Delay()
    69  
    70  	return srv.data[key]
    71  }
    72  
    73  func better(x, y *Data) *Data {
    74  	if x == nil {
    75  		return y
    76  	}
    77  	if y == nil || y.Time.Before(x.Time) {
    78  		return x
    79  	}
    80  	return y
    81  }
    82  
    83  func Write(req *Data) {
    84  	t0 := time.Now()
    85  	done := make(chan bool, len(servers))
    86  
    87  	for _, srv := range servers {
    88  		go func(srv *Server) {
    89  			srv.Write(req)
    90  			done <- true
    91  		}(srv)
    92  	}
    93  
    94  	for n := 0; n < WriteQuorum; n++ {
    95  		<-done
    96  	}
    97  
    98  	if delay {
    99  		fmt.Printf("write committed at %.3f seconds\n", time.Since(t0).Seconds())
   100  	}
   101  	for n := WriteQuorum; n < N; n++ {
   102  		<-done
   103  	}
   104  	if delay {
   105  		fmt.Printf("all replicas written at %.3f seconds\n", time.Since(t0).Seconds())
   106  	}
   107  }
   108  
   109  func Read(key string) {
   110  	t0 := time.Now()
   111  	replies := make(chan *Data, len(servers))
   112  
   113  	for _, srv := range servers {
   114  		go func(srv *Server) {
   115  			replies <- srv.Read(key)
   116  		}(srv)
   117  	}
   118  
   119  	var d *Data
   120  	for n := 0; n < ReadQuorum; n++ {
   121  		d = better(d, <-replies)
   122  	}
   123  
   124  	if delay {
   125  		fmt.Printf("read committed at %.3f seconds\n", time.Since(t0).Seconds())
   126  	}
   127  
   128  	for n := ReadQuorum; n < N; n++ {
   129  		<-replies
   130  	}
   131  	if delay {
   132  		fmt.Printf("all replicas read at %.3f seconds\n", time.Since(t0).Seconds())
   133  	}
   134  }
   135  
   136  var servers []*Server
   137  
   138  func main() {
   139  	servers = make([]*Server, N)
   140  	for i := range servers {
   141  		servers[i] = new(Server)
   142  	}
   143  
   144  	rand.Seed(time.Now().UnixNano())
   145  
   146  	delay = false
   147  	Write(&Data{"hello", "there", time.Now()})
   148  	time.Sleep(1 * time.Millisecond)
   149  
   150  	Write(&Data{"hello", "world", time.Now()})
   151  
   152  	delay = true
   153  	Read("hello")
   154  }