github.com/qri-io/qri@v0.10.1-0.20220104210721-c771715036cb/logbook/oplog/simulate_test.go (about)

     1  package oplog
     2  
     3  import (
     4  	"context"
     5  	"fmt"
     6  	"math/rand"
     7  	"testing"
     8  	"time"
     9  )
    10  
    11  func TestSimulateLogReplication(t *testing.T) {
    12  	t.Skip("TODO (b5): restore simulation test")
    13  
    14  	ctx, done := context.WithCancel(context.Background())
    15  	defer done()
    16  
    17  	og := &opGenerator{ctx: ctx, NoopProb: 95}
    18  	sim := NewSimulation(ctx, 5, og)
    19  	sim.Setup()
    20  	sim.Run(100)
    21  
    22  	fmt.Println("ops generated", og.opsGenerated)
    23  	// for _, p := range sim.Peers {
    24  	// 	fmt.Printf("peer %d. sent: %d \treceived: %d \tlen: %d\n", p.ID, p.msgsSent, p.msgsReceived, p.Log.Len())
    25  	// }
    26  
    27  	// for _, p := range sim.Peers {
    28  	// 	fmt.Println()
    29  	// 	state := p.Log.State()
    30  	// 	data, _ := json.Marshal(state)
    31  	// 	fmt.Println(string(data))
    32  	// }
    33  }
    34  
    35  type Simulation struct {
    36  	ctx   context.Context
    37  	Peers []*Peer
    38  }
    39  
    40  func NewSimulation(ctx context.Context, peerCount int, gen *opGenerator) *Simulation {
    41  	s := &Simulation{ctx: ctx, Peers: make([]*Peer, peerCount)}
    42  	for i := 0; i < peerCount; i++ {
    43  		p := &Peer{
    44  			ID:    i,
    45  			Log:   Log{},
    46  			Inbox: make(chan Op, peerCount),
    47  
    48  			ops:   gen,
    49  			ticks: make(chan struct{}),
    50  		}
    51  		s.Peers[i] = p
    52  	}
    53  
    54  	return s
    55  }
    56  
    57  func (s Simulation) Setup() {
    58  	// wire up all peers into a star topology
    59  	for i, a := range s.Peers {
    60  		a.Start(s.ctx)
    61  		for _, b := range s.Peers[i+1:] {
    62  			a.Downstreams = append(a.Downstreams, b.Inbox)
    63  			b.Downstreams = append(b.Downstreams, a.Inbox)
    64  		}
    65  	}
    66  }
    67  
    68  func (s Simulation) Run(ticks int) {
    69  	for t := 0; t <= ticks; t++ {
    70  		for _, p := range s.Peers {
    71  			p.Tick(t)
    72  		}
    73  	}
    74  
    75  	for _, p := range s.Peers {
    76  		p.Finalize()
    77  	}
    78  }
    79  
    80  type opGenerator struct {
    81  	ctx          context.Context
    82  	NoopProb     int
    83  	opsGenerated int
    84  }
    85  
    86  func (og *opGenerator) MaybeGen(id int) Op {
    87  	var o Op
    88  	i := rand.Intn(100)
    89  	if i > og.NoopProb {
    90  		//  Author: fmt.Sprintf("%d", id)
    91  		o = Op{Ref: fmt.Sprintf("%d", og.opsGenerated), Note: fmt.Sprintf("op number %d", og.opsGenerated)}
    92  		og.opsGenerated++
    93  	}
    94  
    95  	return o
    96  }
    97  
    98  func (og *opGenerator) Gen() Op {
    99  	//  Author: fmt.Sprintf("%d", id)
   100  	o := Op{
   101  		Ref:       fmt.Sprintf("hash_number_%d_plus_somefiller_text", og.opsGenerated),
   102  		Prev:      fmt.Sprintf("hash_number_%d_plus_somefiller_text", og.opsGenerated-1),
   103  		Timestamp: time.Now().UnixNano(),
   104  		Note:      fmt.Sprintf("op number %d with a long description that shows how stuff gets long and stuff", og.opsGenerated),
   105  	}
   106  	og.opsGenerated++
   107  
   108  	return o
   109  }
   110  
   111  type Peer struct {
   112  	ID          int
   113  	Log         Log
   114  	Inbox       chan Op
   115  	Downstreams []chan Op
   116  
   117  	ops          *opGenerator
   118  	message      *Op
   119  	msgsSent     int
   120  	msgsReceived int
   121  	ticks        chan struct{}
   122  }
   123  
   124  func (p *Peer) Start(ctx context.Context) {
   125  	go func() {
   126  		for {
   127  			<-p.ticks
   128  			// fmt.Printf("%d ticked\n", p.ID)
   129  			select {
   130  			case msg := <-p.Inbox:
   131  				p.message = &msg
   132  			case <-ctx.Done():
   133  				return
   134  			}
   135  		}
   136  	}()
   137  }
   138  
   139  func (p *Peer) Tick(t int) {
   140  	go func() { p.ticks <- struct{}{} }()
   141  
   142  	if p.message != nil {
   143  		p.processMessage()
   144  		return
   145  	}
   146  
   147  	op := p.ops.MaybeGen(p.ID)
   148  	// TODO (b5) - need to restore with a new mechanism for put
   149  	// p.Log = p.Log.Put(op)
   150  	p.msgsSent++
   151  	for _, ds := range p.Downstreams {
   152  		ds <- op
   153  	}
   154  }
   155  
   156  func (p *Peer) Finalize() {
   157  	for len(p.Inbox) > 0 {
   158  		fmt.Println("draining message")
   159  		msg := <-p.Inbox
   160  		p.message = &msg
   161  		p.processMessage()
   162  	}
   163  }
   164  
   165  func (p *Peer) processMessage() {
   166  	// op := *p.message
   167  	p.msgsReceived++
   168  	// TODO (b5) - need to restore with a new mechanism for put
   169  	// p.Log = p.Log.Put(op)
   170  	p.message = nil
   171  }