func (fwd *forwarder) Forward(q *proto.XCreatePost, forwarded bool) error { if len(fwd.filter) > 0 { if _, ok := fwd.filter[q.TimelineID]; !ok { return nil } } if forwarded { fwd.IncReqFwd() } else { fwd.IncReqFire() } sh := fwd.timelines.Find(proto.ShardKeyOf(q.TimelineID)) if sh == nil { panic("no shard for timelineID") } // Service request at this timeline if sh.Pivot == fwd.here.Pivot { defer fwd.IncServed() return fwd.srv.CreatePost(q) } if forwarded { return errors.New("re-forwarding") } // Forward request to another timeline node defer fwd.IncForwarded() return fwd.forward(q, sh) }
// queryTimelineDirectly queries the timeline shard for timelineID directly. // It fetches and stores the result locally, after which it returns the result. func (srv *DashboardServer) queryTimelineDirectly(timelineID, beforePostID int64, limit int) ([]*proto.Post, error) { // Compute shard where timeline resides sh := srv.timelines.Find(proto.ShardKeyOf(timelineID)) if sh == nil { panic("no shard for timelineID") } // Connect to shard conn := srv.dialer.Dial(sh.Addr) defer conn.Close() // Fire request err := conn.Write( &proto.XTimelineQuery{ TimelineID: timelineID, BeforePostID: beforePostID, Limit: limit + 1, // Request one more than limit, so we can create limit cache rows }, ) if err != nil { return nil, err } // Wait for response resp, err := conn.Read() if err != nil { return nil, err } switch q := resp.(type) { case *proto.XError: return nil, errors.New(fmt.Sprintf("remote timeline returned error (%s)", q.Error)) case *proto.XTimelineQuerySuccess: if len(q.Posts) == 0 { return nil, nil } result := make([]*proto.Post, min(len(q.Posts), limit)) for i, _ := range result { result[i] = &proto.Post{TimelineID: timelineID, PostID: q.Posts[i]} } // Cache the responses in the local db permanently for i := 0; i+1 < len(q.Posts); i++ { if err := srv.cache(timelineID, q.Posts[i], q.Posts[i+1]); err != nil { return nil, err } } if len(q.Posts) < limit+1 { // Fewer posts than requested were returned, implying that there are no posts prior to // the last returned post. We cache that fact below. if err := srv.cache(timelineID, q.Posts[len(q.Posts)-1], 0); err != nil { return nil, err } } return result, nil } return nil, errors.New("unknown response") }
func (fwd *forwarder) Forward(q *proto.XDashboardQuery, alreadyForwarded bool) ([]*proto.Post, error) { sh := fwd.dashboards.Find(proto.ShardKeyOf(q.DashboardID)) if sh == nil { panic("no shard for dashboardID") } // Service request locally if sh.Pivot == fwd.here.Pivot { return fwd.srv.Query(q) } if alreadyForwarded { return nil, errors.New("re-forwarding") } // Forward request to another timeline node return fwd.forward(q, sh) }
// ShardKey returns an xor.Key which determines in which timeline shard this row belongs. func (rowKey *RowKey) ShardKey() xor.Key { return proto.ShardKeyOf(rowKey.TimelineID) }