func (self *CoordinatorImpl) ReplicateDelete(request *protocol.Request) error { id := atomic.AddUint32(&self.requestId, uint32(1)) request.Id = &id server := self.clusterConfiguration.GetServerById(request.OwnerServerId) _, replicas := self.clusterConfiguration.GetReplicas(server, request.Database) request.Type = &replicateDelete self.sendRequestToReplicas(request, replicas) return nil }
func (self *CoordinatorImpl) ReplicateWrite(request *protocol.Request) error { id := atomic.AddUint32(&self.requestId, uint32(1)) request.Id = &id location := common.RingLocation(request.Database, request.Series.Name, request.Series.Points[0].Timestamp) replicas := self.clusterConfiguration.GetServersByRingLocation(request.Database, &location) request.Type = &replicateWrite self.sendRequestToReplicas(request, replicas) return nil }
func (self *ShardData) LogAndHandleDestructiveQuery(querySpec *parser.QuerySpec, request *protocol.Request, response chan *protocol.Response, runLocalOnly bool) error { requestNumber, err := self.wal.AssignSequenceNumbersAndLog(request, self) if err != nil { return err } var localResponses chan *protocol.Response if self.localShard != nil { localResponses = make(chan *protocol.Response, 1) // this doesn't really apply at this point since destructive queries don't output anything, but it may later maxPointsFromDestructiveQuery := 1000 processor := engine.NewPassthroughEngine(localResponses, maxPointsFromDestructiveQuery) err := self.localShard.Query(querySpec, processor) processor.Close() if err != nil { return err } } if !runLocalOnly { responses := make([]chan *protocol.Response, len(self.clusterServers), len(self.clusterServers)) for i, server := range self.clusterServers { responseChan := make(chan *protocol.Response, 1) responses[i] = responseChan // do this so that a new id will get assigned request.Id = nil server.MakeRequest(request, responseChan) } for i, responseChan := range responses { for { res := <-responseChan if *res.Type == endStreamResponse { self.wal.Commit(requestNumber, self.clusterServers[i].Id) break } response <- res } } } if localResponses != nil { for { res := <-localResponses if *res.Type == endStreamResponse { self.wal.Commit(requestNumber, self.localServerId) break } response <- res } } response <- &protocol.Response{Type: &endStreamResponse} return nil }
func (self *ShardData) forwardRequest(request *p.Request) ([]<-chan *p.Response, []uint32, error) { ids := []uint32{} responses := []<-chan *p.Response{} for _, server := range self.clusterServers { responseChan := make(chan *p.Response, 1) // do this so that a new id will get assigned request.Id = nil log.Debug("Forwarding request %s to %d", request.GetDescription(), server.Id) server.MakeRequest(request, responseChan) responses = append(responses, responseChan) ids = append(ids, server.Id) } return responses, ids, nil }
// Makes a request to the server. If the responseStream chan is not nil it will expect a response from the server // with a matching request.Id. The REQUEST_RETRY_ATTEMPTS constant of 3 and the RECONNECT_RETRY_WAIT of 100ms means // that an attempt to make a request to a downed server will take 300ms to time out. func (self *ProtobufClient) MakeRequest(request *protocol.Request, responseStream chan *protocol.Response) error { if request.Id == nil { id := atomic.AddUint32(&self.lastRequestId, uint32(1)) request.Id = &id } if responseStream != nil { self.requestBufferLock.Lock() // this should actually never happen. The sweeper should clear out dead requests // before the uint32 ids roll over. if oldReq, alreadyHasRequestById := self.requestBuffer[*request.Id]; alreadyHasRequestById { message := "already has a request with this id, must have timed out" log.Error(message) oldReq.responseChan <- &protocol.Response{Type: &endStreamResponse, ErrorMessage: &message} } self.requestBuffer[*request.Id] = &runningRequest{timeMade: time.Now(), responseChan: responseStream, request: request} self.requestBufferLock.Unlock() } data, err := request.Encode() if err != nil { return err } conn := self.getConnection() if conn == nil { conn = self.reconnect() if conn == nil { return fmt.Errorf("Failed to connect to server %s", self.hostAndPort) } } if self.writeTimeout > 0 { conn.SetWriteDeadline(time.Now().Add(self.writeTimeout)) } buff := bytes.NewBuffer(make([]byte, 0, len(data)+8)) binary.Write(buff, binary.LittleEndian, uint32(len(data))) _, err = conn.Write(append(buff.Bytes(), data...)) if err == nil { return nil } // if we got here it errored out, clear out the request self.requestBufferLock.Lock() delete(self.requestBuffer, *request.Id) self.requestBufferLock.Unlock() self.reconnect() return err }