Example #1
0
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)
}
Example #2
0
// 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")
}
Example #3
0
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)
}
Example #4
0
// 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)
}