// This method returns a function that can be passed into the datastore's ExecuteQuery method. It will tell the datastore // if each point is something that should be returned in the query based on its ring location and if the query calls for // data from different replicas. // // Params: // - database: the name of the database // - countOfServersToInclude: the number of replicas that this server will return data for // // Returns a function that returns true if the point should be filtered out. Otherwise the point should be included // in the yielded time series func (self *ClusterConfiguration) GetRingFilterFunction(database string, countOfServersToInclude uint32) func(database, series *string, time *int64) bool { serversToInclude := make([]*ClusterServer, 0, countOfServersToInclude) countServers := int(countOfServersToInclude) for i, s := range self.servers { if s.Id == self.localServerId { serversToInclude = append(serversToInclude, s) for j := i - 1; j >= 0 && len(serversToInclude) < countServers; j-- { serversToInclude = append(serversToInclude, self.servers[j]) } if len(serversToInclude) < countServers { for j := len(self.servers) - 1; len(serversToInclude) < countServers; j-- { serversToInclude = append(serversToInclude, self.servers[j]) } } } } f := func(database, series *string, time *int64) bool { location := common.RingLocation(database, series, time) server := self.servers[location%len(self.servers)] for _, s := range serversToInclude { if s.Id == server.Id { return false } } return true } return f }
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 *CoordinatorImpl) CommitSeriesData(db string, series *protocol.Series) error { // break the series object into separate ones based on their ring location // if times server assigned, all the points will go to the same place serverAssignedTime := true now := common.CurrentTime() // assign sequence numbers lastNumber, err := self.datastore.AtomicIncrement(POINT_SEQUENCE_NUMBER_KEY, len(series.Points)) if err != nil { return err } lastNumber = lastNumber - uint64(len(series.Points)-1) for _, p := range series.Points { if p.Timestamp == nil { p.Timestamp = &now } else { serverAssignedTime = false } if p.SequenceNumber == nil { n := self.sequenceNumberWithServerId(lastNumber) lastNumber++ p.SequenceNumber = &n } } // if it's a single server setup, we don't need to bother with getting ring // locations or logging requests or any of that, so just write to the local db and be done. if self.clusterConfiguration.IsSingleServer() { err := self.writeSeriesToLocalStore(&db, series) return err } if serverAssignedTime { location := common.RingLocation(&db, series.Name, series.Points[0].Timestamp) i := self.clusterConfiguration.GetServerIndexByLocation(&location) return self.handleClusterWrite(&i, &db, series) } // TODO: make this more efficient and not suck so much // not all the same, so break things up seriesToServerIndex := make(map[int]*protocol.Series) for _, p := range series.Points { location := common.RingLocation(&db, series.Name, p.Timestamp) i := self.clusterConfiguration.GetServerIndexByLocation(&location) s := seriesToServerIndex[i] if s == nil { s = &protocol.Series{Name: series.Name, Fields: series.Fields, Points: make([]*protocol.Point, 0)} seriesToServerIndex[i] = s } s.Points = append(s.Points, p) } for serverIndex, s := range seriesToServerIndex { err := self.handleClusterWrite(&serverIndex, &db, s) if err != nil { return err } } return nil }
func (self *ProtobufRequestHandler) HandleRequest(request *protocol.Request, conn net.Conn) error { if *request.Type == protocol.Request_PROXY_WRITE { response := &protocol.Response{RequestId: request.Id, Type: &self.writeOk} location := common.RingLocation(request.Database, request.Series.Name, request.Series.Points[0].Timestamp) ownerId := self.clusterConfig.GetOwnerIdByLocation(&location) request.OriginatingServerId = &self.clusterConfig.localServerId // TODO: make request logging and datastore write atomic replicationFactor := self.clusterConfig.GetReplicationFactor(request.Database) err := self.db.LogRequestAndAssignSequenceNumber(request, &replicationFactor, ownerId) if err != nil { return err } err = self.db.WriteSeriesData(*request.Database, request.Series) if err != nil { return err } err = self.WriteResponse(conn, response) // TODO: add quorum writes? self.coordinator.ReplicateWrite(request) return err } else if *request.Type == protocol.Request_PROXY_DELETE { response := &protocol.Response{RequestId: request.Id, Type: &self.writeOk} request.OriginatingServerId = &self.clusterConfig.localServerId // TODO: make request logging and datastore write atomic replicationFactor := self.clusterConfig.GetReplicationFactor(request.Database) err := self.db.LogRequestAndAssignSequenceNumber(request, &replicationFactor, request.OwnerServerId) if err != nil { return err } query, _ := parser.ParseQuery(*request.Query) err = self.db.DeleteSeriesData(*request.Database, query[0].DeleteQuery) if err != nil { return err } err = self.WriteResponse(conn, response) // TODO: add quorum writes? self.coordinator.ReplicateDelete(request) return err } else if *request.Type == protocol.Request_REPLICATION_WRITE { replicationFactor := self.clusterConfig.GetReplicationFactor(request.Database) // TODO: make request logging and datastore write atomic err := self.db.LogRequestAndAssignSequenceNumber(request, &replicationFactor, request.OwnerServerId) if err != nil { switch err := err.(type) { case datastore.SequenceMissingRequestsError: go self.coordinator.ReplayReplication(request, &replicationFactor, request.OwnerServerId, &err.LastKnownRequestSequence) return nil default: return err } } self.db.WriteSeriesData(*request.Database, request.Series) return nil } else if *request.Type == protocol.Request_REPLICATION_DELETE { replicationFactor := self.clusterConfig.GetReplicationFactor(request.Database) // TODO: make request logging and datastore write atomic err := self.db.LogRequestAndAssignSequenceNumber(request, &replicationFactor, request.OwnerServerId) if err != nil { switch err := err.(type) { case datastore.SequenceMissingRequestsError: go self.coordinator.ReplayReplication(request, &replicationFactor, request.OwnerServerId, &err.LastKnownRequestSequence) return nil default: return err } } query, _ := parser.ParseQuery(*request.Query) return self.db.DeleteSeriesData(*request.Database, query[0].DeleteQuery) } else if *request.Type == protocol.Request_QUERY { go self.handleQuery(request, conn) } else if *request.Type == protocol.Request_REPLICATION_REPLAY { self.handleReplay(request, conn) } else { log.Error("unknown request type: %v", request) return errors.New("Unknown request type") } return nil }