github.com/DARA-Project/GoDist-Scheduler@v0.0.0-20201030134746-668de4acea0d/structured/rsm/kvlib/kvlib.go (about)

     1  package kvlib
     2  
     3  import (
     4  	"net/rpc"
     5  	"errors"
     6  	"time"
     7  	"sync"
     8  )
     9  
    10  // args in get(args)
    11  type GetArgs struct {
    12  	Key      string // key to look up
    13  	Clientid uint8  // client id issuing this get
    14  	Clock    uint64 // value of lamport clock at the issuing client
    15  }
    16  
    17  // args in put(args)
    18  type PutArgs struct {
    19  	Key      string // key to associate value with
    20  	Val      string // value
    21  	Clientid uint8  // client id issueing this put
    22  	Clock    uint64 // value of lamport clock at the issuing client
    23  }
    24  
    25  // args in clockupdate(args)
    26  type ClockUpdateArgs struct {
    27  	Clientid uint8  // client id issueing this put
    28  	Clock    uint64 // value of lamport clock at the issuing client
    29  }
    30  
    31  // args in disconnect(args)
    32  type DisconnectArgs struct {
    33  	Clientid uint8 // client id issueing this put
    34  }
    35  
    36  // Reply from service for all the API calls above.
    37  type ValReply struct {
    38  	Val string // value; depends on the call
    39  }
    40  
    41  type KVService struct {
    42  	Clientid uint8
    43  	ClockUpdateRate uint8
    44  	Clock uint64
    45  	Replicas []*rpc.Client
    46  	Mux sync.Mutex
    47  }
    48  
    49  func (kv *KVService) Get(key string) (string, error) {
    50  	var err error
    51  	kv.Mux.Lock()
    52  	kv.Clock += 1
    53  	args := GetArgs{key, kv.Clientid, kv.Clock}
    54  	kv.Mux.Unlock()
    55  	var reply ValReply
    56  	for _, c := range kv.Replicas {
    57  		err = c.Call("KeyValService.Get", &args, &reply)
    58  		if err == nil {
    59  			return reply.Val, nil
    60  		}
    61  	}
    62  	return reply.Val, err
    63  }
    64  
    65  func (kv *KVService) Put(key string, val string) error {
    66  	var err error
    67  	kv.Mux.Lock()
    68  	kv.Clock += 1
    69  	putArgs := PutArgs{key, val, kv.Clientid, kv.Clock}
    70  	kv.Mux.Unlock()
    71  	var reply ValReply
    72  	num_errors := 0
    73  	for _, c := range kv.Replicas {
    74  		err = c.Call("KeyValService.Put", &putArgs, &reply)
    75  		if err != nil {
    76  			num_errors += 1
    77  		}
    78  	}
    79  	if num_errors == len(kv.Replicas) {
    80  		return errors.New("All replicas failed.")
    81  	}
    82  	return nil
    83  }
    84  
    85  func (kv *KVService) Disconnect() error {
    86  	var err error
    87  	kv.Mux.Lock()
    88  	kv.Clock += 1
    89  	kv.Mux.Unlock()
    90  	dcArgs := DisconnectArgs{kv.Clientid}
    91  	var reply ValReply
    92  	for _, c := range kv.Replicas {
    93  		err = c.Call("KeyValService.Disconnect", &dcArgs, &reply)
    94  	}
    95  	return err
    96  }
    97  
    98  func (kv *KVService) clockUpdate() {
    99  	ticker := time.NewTicker(time.Duration(kv.ClockUpdateRate) * time.Millisecond)
   100  	for {
   101  		select {
   102  			case <- ticker.C:
   103  				kv.Mux.Lock()
   104  				kv.Clock += 1
   105  				kv.Mux.Unlock()
   106  				args := ClockUpdateArgs{kv.Clientid, kv.Clock}
   107  				var reply ValReply
   108  				for _, c := range kv.Replicas {
   109  					c.Call("KeyValService.ClockUpdate", &args, &reply)
   110  				}
   111  		}
   112  	}
   113  }
   114  
   115  func Init(id uint8, updateRate uint8, addresses []string) (*KVService, error) {
   116  	clients := []*rpc.Client{}
   117  	for _, s := range addresses {
   118  		client, err := rpc.Dial("tcp", s)
   119  		if err != nil {
   120  			return nil, err
   121  		}
   122  		clients = append(clients, client)
   123  	}
   124  	kvService := &KVService{Clientid : id, ClockUpdateRate : updateRate, Clock : 0, Replicas : clients}
   125  	go kvService.clockUpdate()
   126  	return kvService, nil
   127  }