Пример #1
0
func (s *testPBServer) Get() (View, error) {
	args := new(ConsultArgs)
	reply := new(ConsultReply)

	err := rpc.Call(s.server, "ViewServer.Get", args, reply)

	return reply.View, err
}
Пример #2
0
func (s *testPBServer) Ping(n uint32) (View, error) {
	args := &PingArgs{
		Addr:         s.addr,
		SerialNumber: n,
	}
	reply := new(PingReply)

	err := rpc.Call(s.server, "ViewServer.Ping", args, reply)

	return reply.View, err
}
Пример #3
0
// Get current view from view server.
func (c *testClient) updateView() {
	args := &ConsultArgs{}
	reply := new(ConsultReply)

	//TODO Move retransfer manchism to rpc framework.
	for cnt := 0; cnt < RetransferThreshold; cnt++ {
		err := rpc.Call(c.server, "ViewServer.Get", args, reply)
		if err != nil {
			logger.Error(fmt.Sprintf("CLient get view error: %s", err))
		} else {
			c.view = reply.View
			break
		}
		time.Sleep(RetransferWaitInterval[cnt])
	}
}
Пример #4
0
// Stop the master and all workers.
func (m *Master) shutdown() {
	logger.Info("Closing master...")

	m.idleWorkers.Close()
	rpc.Close(m)

	args := new(ShutdownArgs)
	reply := new(ShutdownReply)

	for _, w := range m.workers {
		if err := rpc.Call(w, "Worker.Shutdown", args, reply); err != nil {
			logger.Info(fmt.Sprintf("Worker %s shutdown error: %s", w, err))
		} else {
			logger.Info(fmt.Sprintf("Worker %s runs %d mappers, %d reducers",
				w, reply.MapperNum, reply.ReducerNum))
		}
	}

	logger.Info("Close master done")
}
Пример #5
0
func (w *Worker) run() {
	// Register as a rpc server
	rpc.Register(w, w.address)

	// Register as a worker for master.
	args := &RegisterArgs{
		Worker: w.address,
	}
	reply := new(RegisterReply)
	err := rpc.Call(masterAddress, "Master.Register", args, reply)
	if err != nil {
		logger.Error(fmt.Sprintf("Cannot register %s as a worker", err))
		rpc.Close(w)
		return
	}

	w.file = reply.File
	w.mapper = reply.CMapper
	w.reducer = reply.CReducer
	w.nMapper = reply.NumMapper
	w.nReducer = reply.NumReducer
}
Пример #6
0
// "op" should be Put or Append.
func (c *testClient) putAppend(key, value string, op string) {
	logger.Info(fmt.Sprintf("Client %s send a %s request to %s", c.addr, op,
		c.view.Primary))

	args := &PutAppendArgs{
		OperationArgs: OperationArgs{
			Source:    Client,
			RequsetId: uid(),
		},
		//Source:    Client,
		//RequsetId: uid(),
		Key:   key,
		Value: value,
	}
	reply := new(PutAppendReply)

	// Send request until successed.
	for {
		//TODO Move retransfer mechanism to rpc framework.
		for cnt := 0; cnt < RetransferThreshold; cnt++ {
			err := rpc.Call(c.view.Primary, "PBServer."+op, args, reply)
			if err != nil {
				logger.Error(fmt.Sprintf("%s invoke error: %s", op, err))
			} else {
				break
			}
			time.Sleep(RetransferWaitInterval[cnt])
		}

		if reply.Err.Code == OK {
			return
		} else {
			// Unknown, ErrNotPrimary, ErrServerShutdown. Wait a moment and send again.
			time.Sleep(PingInterval)
			c.updateView()
			logger.Error(reply.Err.Description)
		}
	}
}
Пример #7
0
func (c *testClient) Get(key string) string {
	logger.Info(fmt.Sprintf("Client %s send a Get request to %s", c.addr,
		c.view.Primary))

	args := &GetArgs{
		OperationArgs: OperationArgs{
			Source:    Client,
			RequsetId: uid(),
		},
		Key: key,
	}
	reply := new(GetReply)

	// Send request until successed.
	for {
		//TODO Move retransfer mechanism to rpc framework.
		for cnt := 0; cnt < RetransferThreshold; cnt++ {
			err := rpc.Call(c.view.Primary, "PBServer.Get", args, reply)
			if err != nil {
				logger.Error(fmt.Sprintf("Get invoke error: %s", err))
			} else {
				break
			}
			time.Sleep(RetransferWaitInterval[cnt])
		}

		if reply.Err.Code == OK {
			return reply.Value
		} else if reply.Err.Code == ErrKeyNotFound {
			logger.Error(reply.Err)
			return ""
		} else {
			// ErrNotPrimary, ErrServerShutdown. wait a moment and send again.
			time.Sleep(PingInterval)
			c.updateView()
		}
	}
}
Пример #8
0
func (s *PBServer) Get(args *GetArgs, reply *GetReply) error {
	s.lock()
	defer s.unlock()

	if !s.alive.Get() {
		reply.Err = Error{
			Code:        ErrServerShutdown,
			Description: fmt.Sprintf("Server %s is closed", s.addr),
		}
		return nil
	}

	type rValue struct {
		err   error
		reply GetReply
	}

	// Forward Get request to backup.
	forward := func(r *rValue) bool {
		format := "Forward Get request from %s to %s"
		logger.Info(fmt.Sprintf(format, s.addr, s.view.Backup))

		cached := true
		args.Source = Primary

		//TODO Move retransfer mechanism to rpc framwork.
		for cnt := 0; cnt < RetransferThreshold; cnt++ {
			err := rpc.Call(s.view.Backup, "PBServer.Get", args,
				&(r.reply))

			if err != nil {
				format := "Forward Get request from %s to" +
					" %s error: %s"
				logger.Error(fmt.Sprintf(format, s.addr,
					s.view.Backup, err))
				r.reply.Err.Description = err.Error()
			} else {
				// Stop transfer.
				break
			}
			time.Sleep(RetransferWaitInterval[cnt])
		}

		code := r.reply.Err.Code

		if code == ErrBackupPromoted {
			// backup became new primary, return an error and
			// the client will update current view and try
			// again.
			format := "Server %s is not current primary"
			r.reply.Err = Error{
				Code:        ErrNotPrimary,
				Description: fmt.Sprintf(format, s.addr),
			}

		} else if code != OK &&
			code != ErrKeyNotFound {
			// r.reply.Err.Code == OK indicated that forward
			// success, result is exist, needn't do the query
			// in this server any mall.

			// r.reply.Err.Code == ErrKeyNotFound indicated
			// that key not exist, needn't do query on this
			// server any mall.

			// May be backup is modified, return an error,
			// client will try again.
			cached = false
		}
		return cached
	}

	// Handle request from client.
	clientRequest := func(r *rValue) bool {
		format := "Pbserver %s receive Get request from client"
		logger.Info(fmt.Sprintf(format, s.addr))

		cached := true

		if s.addr != s.view.Primary {
			format := "Server %s is not current primary"
			r.reply.Err = Error{
				Code:        ErrNotPrimary,
				Description: fmt.Sprintf(format, s.addr),
			}
			// Can't cache this result as this server perhaps don't konw
			// it is primary yet.
			cached = false
		} else {
			// Get operation also need forward, used to handle the case as
			// follows:
			// Primary is overdue but it didn't know, when client send a
			// Get request to it, the result on this server may be overdue,
			// so it will forward to backup, and backup return an error to
			// indicated this case.
			if s.view.Backup != "" {
				cached = forward(r)
			} else {
				r.err = s.get(args.Key, &(r.reply))
			}
		}
		return cached
	}

	// Handle request forward by primary.
	forwardRequest := func(r *rValue) bool {
		format := "Pbserver %s receive Get request forward by primary"
		logger.Info(fmt.Sprintf(format, s.addr))

		cached := true

		if s.addr != s.view.Backup {
			if s.addr == s.view.Primary {
				// Backup has beeen promoted as new primary.
				format := "Server %s is promoted as new primary"
				r.reply.Err = Error{
					Code:        ErrBackupPromoted,
					Description: fmt.Sprintf(format, s.addr),
				}
				// Can't cache this result as Client will send the same
				// request later.
				cached = false
			} else {
				// This server failed or is not backup.
				format := "Server %s is not current backup"
				r.reply.Err = Error{
					Code:        ErrNotBackup,
					Description: fmt.Sprintf(format, s.addr),
				}
				// Can't cache this result as this server may become
				// backup later.
				cached = false
			}
		} else {
			r.err = s.get(args.Key, &(r.reply))
		}
		return cached
	}

	executor := func(interface{}) (interface{}, bool) {
		r := new(rValue)
		cached := true

		if args.Source == Client {
			// Request from client.
			cached = clientRequest(r)
		} else if args.Source == Primary {
			// Request forward by primary.
			cached = forwardRequest(r)
		} else {
			// Invalid request source.
			format := "Server %s can't process a \"Get\" operation from %s"
			reply.Err = Error{
				Code:        ErrInvalidRequestSource,
				Description: fmt.Sprintf(format, s.addr, args.Source),
			}
		}

		return r, cached
	}

	res := s.group.Do(strconv.Itoa(int(args.RequsetId)), nil,
		executor).(*rValue)
	if res.err != nil {
		return res.err
	} else {
		*reply = res.reply
		return nil
	}

}
Пример #9
0
// Send ping signal to view server periodicly.
func (s *PBServer) tick() {
	// Only this method can change s.view's value, so s.view is read safe in
	// this method.
	for s.alive.Get() {
		args := &PingArgs{
			Addr:         s.addr,
			SerialNumber: s.view.SerialNumber,
		}
		reply := new(PingReply)
		err := rpc.Call(s.viewServer, "ViewServer.Ping", args, reply)

		if err != nil {
			//logger.Error(fmt.Sprintf("PBServer(%s) ping error: %s",
			//	s.addr, err))
			continue
		}

		if reply.View.SerialNumber == s.view.SerialNumber {
			// View isn't updated.
			time.Sleep(PingInterval)
			continue
		}

		// Update current view.
		oldView := s.view
		s.lock()
		s.view = reply.View
		s.unlock()

		if s.addr == s.view.Primary {
			// This server became new primary.
			if oldView.Primary != "" && s.addr != oldView.Primary &&
				oldView.Backup != "" && s.addr != oldView.Backup {
				format := "New primary(%s) is not the backup(%s) or" +
					" primary(%s) before"
				logger.Error(fmt.Sprintf(format, s.addr,
					oldView.Backup))
			}
		} else if s.addr == s.view.Backup {
			// This server became new backup.
			// Get the whole database from primary.
			logger.Info(fmt.Sprintf("Pbserver %s send Transfer request to %s",
				s.addr, s.view.Primary))

			targs := &TransferArgs{
				OperationArgs: OperationArgs{
					Source:    Backup,
					RequsetId: uid(),
				},
				Addr: s.addr,
			}
			treply := new(TransferReply)

			// Send request until successed.
			for s.alive.Get() {
				//TODO Move the retransfer mechanism to rpc framework.
				for cnt := 0; cnt < RetransferThreshold; cnt++ {
					err := rpc.Call(s.view.Primary, "PBServer.Transfer", targs,
						treply)
					if err != nil {
						format := "Tansfer data from primary(%s) to backup(%s)" +
							" error: %s"
						logger.Error(fmt.Sprintf(format, s.view.Primary, s.addr,
							err))
						// Wait a moment and try again.
						time.Sleep(RetransferWaitInterval[cnt])
					} else {
						break
					}
				}

				if treply.Err.Code == OK {
					// Update the whole database.
					s.lock()
					s.data = treply.Data
					s.unlock()
					break
				} else if treply.Err.Code == ErrNotPrimary {
					// Wait a moment and try again.
					time.Sleep(PingInterval)
				} else if treply.Err.Code == ErrServerShutdown {
					// Primary is closed before transfer data, this is bug.
					// Just stop sending request.
					break
				} else {
					// Unexpected error.
					format := "Can't transfer data from primary(%s) to " +
						"backup(%s): %s"
					logger.Error(fmt.Sprintf(format, s.view.Primary, s.addr,
						treply.Err.Description))
					break
				}
			}
		} else {
			// Both primary and backup is not empty, this server is not used.
		}
		time.Sleep(PingInterval)
	}

	s.done <- true
}
Пример #10
0
// Executor of Put and Append.
func (s *PBServer) putAppend(args *PutAppendArgs, reply *PutAppendReply,
	op string) error {
	// Check stopped or not.
	if !s.alive.Get() {
		reply.Err = Error{
			Code:        ErrServerShutdown,
			Description: fmt.Sprintf("Server %s is closed", s.addr),
		}
		return nil
	}

	type rValue struct {
		err   error
		reply PutAppendReply
	}

	// Forward request to backup.
	// The first return value is cached, the second return value is go on
	// or not.
	forward := func(r *rValue) (bool, bool) {
		logger.Info(fmt.Sprintf("Forward %s request from %s to %s",
			op, s.addr, s.view.Backup))

		cached := true
		args.Source = Primary

		//TODO Move retransfer mechanism to rpc framework.
		for cnt := 0; cnt < RetransferThreshold; cnt++ {
			err := rpc.Call(s.view.Backup, "PBServer."+op, args,
				&(r.reply))
			if err != nil {
				format := "Forward %s request from %s to " +
					"%s error: %s"
				logger.Error(fmt.Sprintf(format, op, s.addr,
					s.view.Backup, err))
			} else {
				break
			}
			time.Sleep(RetransferWaitInterval[cnt])
		}

		code := r.reply.Err.Code

		if code == OK {
			return cached, true
		} else if code == ErrBackupPromoted {
			// backup became new primary, return an error and
			// the client will update current view and try
			// again.
			format := "Server %s is not current primary"
			r.reply.Err = Error{
				Code:        ErrNotPrimary,
				Description: fmt.Sprintf(format, s.addr),
			}
			return cached, false
		} else {
			// May be backup is modified, return an error,
			// client will try again.
			r.err = fmt.Errorf("Forward error: %s",
				r.reply.Err.Description)
			return false, false
		}
	}

	clientRequest := func(r *rValue) bool {
		format := "Pbserver %s receive %s request from client"
		logger.Info(fmt.Sprintf(format, s.addr, op))

		cached := true

		if s.addr != s.view.Primary {
			format := "Server %s is not current primary"
			r.reply.Err = Error{
				Code:        ErrNotPrimary,
				Description: fmt.Sprintf(format, s.addr),
			}
			// Can't cache this result as this server perhaps don't konw
			// it is primary yet.
			cached = false
		} else {
			if s.view.Backup != "" {
				// Forward request to backup
				var goOn bool
				cached, goOn = forward(r)
				if !goOn {
					return cached
				}
			}
			if op == "Put" {
				s.putValue(args.Key, args.Value)
			} else {
				s.appendValue(args.Key, args.Value)
			}
			r.reply.Err.Code = OK
		}

		return cached
	}

	forwardRequest := func(r *rValue) bool {
		format := "Pbserver %s receive %s request forward by primary"
		logger.Info(fmt.Sprintf(format, s.addr, op))

		cached := true

		if s.addr != s.view.Backup {
			if s.addr == s.view.Primary {
				// Backup has beeen promoted as new primary.
				format := "Server %s is promoted as new primary"
				r.reply.Err = Error{
					Code:        ErrBackupPromoted,
					Description: fmt.Sprintf(format, s.addr),
				}
				// Can't cache this result as Client will send the same
				// request later.
				cached = false
			} else {
				// This server failed or is not backup.
				format := "Server %s is not current backup"
				r.reply.Err = Error{
					Code:        ErrNotBackup,
					Description: fmt.Sprintf(format, s.addr),
				}
				// Can't cache this result as this server may become
				// backup later.
				cached = false
			}
		} else {
			if op == "Put" {
				s.putValue(args.Key, args.Value)
			} else {
				s.appendValue(args.Key, args.Value)
			}
			r.reply.Err.Code = OK
		}

		return cached
	}

	f := func(interface{}) (interface{}, bool) {
		r := new(rValue)
		cached := true

		if args.Source == Client {
			// Request from client.
			cached = clientRequest(r)
		} else if args.Source == Primary {
			// Request forward by primary.
			cached = forwardRequest(r)
		} else {
			format := "Server %s can't process a \"%s\" operation from %s"
			r.reply.Err = Error{
				Code:        ErrInvalidRequestSource,
				Description: fmt.Sprintf(format, s.addr, op, args.Source),
			}
		}

		return r, cached
	}

	res := s.group.Do(strconv.Itoa(int(args.RequsetId)), nil, f).(*rValue)
	if res.err != nil {
		return res.err
	} else {
		*reply = res.reply
		return nil
	}
}