Skip to content
Snippets Groups Projects
Commit 6df69c30 authored by Zeger-Jan van de Weg's avatar Zeger-Jan van de Weg
Browse files

Allow pagination for FindAllLocalBranches

Pagination has always been ad hoc within Gitaly, and there was no
convergence to a standard. This change creates a structure around this,
which an implementation for one RPC to try it.

The structure uses a page token, as proposed in:
#2704 (comment 349733942).
This allows a generic field to hold what's usually a numeric `offset`
field. Where `offset` can be unstable over a series of requests due to
race conditions, the page token could prevent that.

The change does alter the implementation for `lines.Send()` a little,
which create a situation where for other RPCs there's been slight
normalization on their input to `lines.Send()` to make this change
backward as well as forward compatible.

Helps with: gitlab-foss#48097 (comment 354316835)
Part of: #2704
parent 88fa68a3
No related branches found
No related tags found
Loading
Pipeline #154256060 passed with warnings
---
title: Allow pagination for FindAllLocalBranches
merge_request: 2251
author:
type: added
......@@ -6,8 +6,18 @@ import (
"io"
)
// SenderOpts contains fields that Send() uses to determine what is considered
// a line, and how to handle pagination. That is, how many lines to skip, before
// a line gets fed into the Sender.
type SenderOpts struct {
// Defaults to "\n"
Delimiter []byte
// Defaults to 0, Send() only invokes the Sender if the value is over 0
Limit int
// IsPageToken allows control over which results are send as part of the
// response. When IsPageToken evaluates to true for the first time,
// results will start to be send as part of the response.
IsPageToken func([]byte) bool
}
// ItemsPerMessage establishes the threshold to flush the buffer when using the
......@@ -66,7 +76,9 @@ func (w *writer) addLine(p []byte) error {
func (w *writer) consume(r io.Reader) error {
buf := bufio.NewReader(r)
for finished := false; !finished; {
// Allow for IsPageToken: func(_ []byte) bool { return true }
pastPageToken := w.options.IsPageToken([]byte{})
for i := 0; i < w.options.Limit; {
var line []byte
for {
......@@ -83,16 +95,25 @@ func (w *writer) consume(r io.Reader) error {
}
if err == io.EOF {
finished = true
i = w.options.Limit // Implicit exit clause for the loop
break
}
}
line = bytes.TrimRight(line, string(w.delimiter()))
line = bytes.TrimSuffix(line, w.delimiter())
if len(line) == 0 {
break
}
// Pagination skips until the first result is send, when the
// first result is send, the next will always be send too, unless
// the limit has been hit.
if !pastPageToken {
pastPageToken = w.options.IsPageToken(line)
continue
}
i++ // Only increment the counter if the result wasn't skipped
if err := w.addLine(line); err != nil {
return err
}
......@@ -103,13 +124,17 @@ func (w *writer) consume(r io.Reader) error {
func (w *writer) delimiter() []byte { return w.options.Delimiter }
// Send reads output from `r`, splits it at `opts.Delimiter``, then handles the
// Send reads output from `r`, splits it at `opts.Delimiter`, then handles the
// buffered lines using `sender`.
func Send(r io.Reader, sender Sender, opts SenderOpts) error {
if len(opts.Delimiter) == 0 {
opts.Delimiter = []byte{'\n'}
}
if opts.IsPageToken == nil {
opts.IsPageToken = func(_ []byte) bool { return true }
}
writer := &writer{sender: sender, options: opts}
return writer.consume(r)
}
......@@ -8,18 +8,59 @@ import (
)
func TestLinesSend(t *testing.T) {
reader := bytes.NewBufferString("mepmep foo bar")
var out [][]byte
sender := func(in [][]byte) error { out = in; return nil }
err := Send(reader, sender, SenderOpts{Delimiter: []byte(" ")})
require.NoError(t, err)
expected := [][]byte{
[]byte("mepmep"),
[]byte("foo"),
[]byte("bar"),
}
require.Equal(t, expected, out)
tcs := []struct {
desc string
limit int
isPageToken func([]byte) bool
output [][]byte
}{
{
desc: "high limit",
limit: 100,
output: expected,
},
{
desc: "limit is 0",
limit: 0,
output: [][]byte(nil),
},
{
desc: "limit 2",
limit: 2,
output: expected[0:2],
},
{
desc: "skip lines",
limit: 100,
isPageToken: func(line []byte) bool { return bytes.HasPrefix(line, expected[0]) },
output: expected[1:3],
},
{
desc: "skip no lines",
limit: 100,
isPageToken: func(_ []byte) bool { return true },
output: expected,
},
}
for _, tc := range tcs {
t.Run(tc.desc, func(t *testing.T) {
reader := bytes.NewBufferString("mepmep\nfoo\nbar")
var out [][]byte
sender := func(in [][]byte) error { out = in; return nil }
err := Send(reader, sender, SenderOpts{
Limit: tc.limit,
IsPageToken: tc.isPageToken,
})
require.NoError(t, err)
require.Equal(t, tc.output, out)
})
}
}
......@@ -6,6 +6,7 @@ import (
"context"
"errors"
"fmt"
"math"
"strings"
"github.com/golang/protobuf/proto"
......@@ -32,10 +33,9 @@ var (
)
type findRefsOpts struct {
cmdArgs []git.Option
delim []byte
pageToken string
limit uint32
cmdArgs []git.Option
delim []byte
lines.SenderOpts
}
func findRefs(ctx context.Context, writer lines.Sender, repo *gitalypb.Repository, patterns []string, opts *findRefsOpts) error {
......@@ -56,7 +56,11 @@ func findRefs(ctx context.Context, writer lines.Sender, repo *gitalypb.Repositor
return err
}
if err := lines.Send(cmd, writer, lines.SenderOpts{Delimiter: opts.delim}); err != nil {
if err := lines.Send(cmd, writer, lines.SenderOpts{
IsPageToken: opts.IsPageToken,
Delimiter: opts.delim,
Limit: int(opts.Limit),
}); err != nil {
return err
}
......@@ -289,12 +293,11 @@ func findLocalBranches(in *gitalypb.FindLocalBranchesRequest, stream gitalypb.Re
}
writer := newFindLocalBranchesWriter(stream, c)
opts := &findRefsOpts{
cmdArgs: []git.Option{
// %00 inserts the null character into the output (see for-each-ref docs)
git.Flag{"--format=" + strings.Join(localBranchFormatFields, "%00")},
git.Flag{"--sort=" + parseSortKey(in.GetSortBy())},
},
opts := paginationParamsToOpts(in.GetPaginationParams())
opts.cmdArgs = []git.Option{
// %00 inserts the null character into the output (see for-each-ref docs)
git.Flag{"--format=" + strings.Join(localBranchFormatFields, "%00")},
git.Flag{"--sort=" + parseSortKey(in.GetSortBy())},
}
return findRefs(ctx, writer, in.Repository, []string{"refs/heads"}, opts)
......@@ -339,9 +342,9 @@ func findAllBranches(in *gitalypb.FindAllBranchesRequest, stream gitalypb.RefSer
return err
}
opts := &findRefsOpts{
cmdArgs: args,
}
opts := paginationParamsToOpts(nil)
opts.cmdArgs = args
writer := newFindAllBranchesWriter(stream, c)
return findRefs(ctx, writer, in.Repository, patterns, opts)
......@@ -446,3 +449,23 @@ func validateFindTagRequest(in *gitalypb.FindTagRequest) error {
}
return nil
}
func paginationParamsToOpts(p *gitalypb.PaginationParameter) *findRefsOpts {
opts := &findRefsOpts{}
opts.IsPageToken = func(_ []byte) bool { return true }
opts.Limit = math.MaxInt32
if p == nil {
return opts
}
if p.GetLimit() >= 0 {
opts.Limit = int(p.GetLimit())
}
if p.GetPageToken() != "" {
opts.IsPageToken = func(l []byte) bool { return bytes.Compare(l, []byte(p.GetPageToken())) >= 0 }
}
return opts
}
......@@ -895,6 +895,69 @@ func TestSuccessfulFindLocalBranches(t *testing.T) {
}
}
func TestFindLocalBranchesPagination(t *testing.T) {
stop, serverSocketPath := runRefServiceServer(t)
defer stop()
client, conn := newRefServiceClient(t, serverSocketPath)
defer conn.Close()
testRepo, _, cleanupFn := testhelper.NewTestRepo(t)
defer cleanupFn()
ctx, cancel := testhelper.Context()
defer cancel()
limit := 1
rpcRequest := &gitalypb.FindLocalBranchesRequest{
Repository: testRepo,
PaginationParams: &gitalypb.PaginationParameter{
Limit: int32(limit),
PageToken: "refs/heads/gitaly/squash-test",
},
}
c, err := client.FindLocalBranches(ctx, rpcRequest)
if err != nil {
t.Fatal(err)
}
var branches []*gitalypb.FindLocalBranchResponse
for {
r, err := c.Recv()
if err == io.EOF {
break
}
require.NoError(t, err)
if err != nil {
t.Fatal(err)
}
branches = append(branches, r.GetBranches()...)
}
require.Len(t, branches, limit)
expectedBranch := "refs/heads/improve/awesome"
target := localBranches[expectedBranch]
branch := &gitalypb.FindLocalBranchResponse{
Name: []byte(expectedBranch),
CommitId: target.Id,
CommitSubject: target.Subject,
CommitAuthor: &gitalypb.FindLocalBranchCommitAuthor{
Name: target.Author.Name,
Email: target.Author.Email,
Date: target.Author.Date,
},
CommitCommitter: &gitalypb.FindLocalBranchCommitAuthor{
Name: target.Committer.Name,
Email: target.Committer.Email,
Date: target.Committer.Date,
},
Commit: target,
}
assertContainsLocalBranch(t, branches, branch)
}
// Test that `s` contains the elements in `relativeOrder` in that order
// (relative to each other)
func isOrderedSubset(subset, set []string) bool {
......
......@@ -35,9 +35,8 @@ func findAllRemoteBranches(req *gitalypb.FindAllRemoteBranchesRequest, stream gi
return err
}
opts := &findRefsOpts{
cmdArgs: args,
}
opts := paginationParamsToOpts(nil)
opts.cmdArgs = args
writer := newFindAllRemoteBranchesWriter(stream, c)
return findRefs(ctx, writer, req.GetRepository(), patterns, opts)
......
......@@ -116,6 +116,8 @@ func newRefServiceClient(t *testing.T, serverSocketPath string) (gitalypb.RefSer
}
func assertContainsLocalBranch(t *testing.T, branches []*gitalypb.FindLocalBranchResponse, branch *gitalypb.FindLocalBranchResponse) {
t.Helper()
for _, b := range branches {
if bytes.Equal(branch.Name, b.Name) {
if !testhelper.FindLocalBranchResponsesEqual(branch, b) {
......@@ -129,6 +131,8 @@ func assertContainsLocalBranch(t *testing.T, branches []*gitalypb.FindLocalBranc
}
func assertContainsBranch(t *testing.T, branches []*gitalypb.FindAllBranchesResponse_Branch, branch *gitalypb.FindAllBranchesResponse_Branch) {
t.Helper()
var branchNames [][]byte
for _, b := range branches {
......
......@@ -5,6 +5,7 @@ import (
"bytes"
"errors"
"io"
"math"
"gitlab.com/gitlab-org/gitaly/internal/command"
"gitlab.com/gitlab-org/gitaly/internal/git"
......@@ -123,7 +124,7 @@ func (s *server) SearchFilesByName(req *gitalypb.SearchFilesByNameRequest, strea
return stream.Send(&gitalypb.SearchFilesByNameResponse{Files: objs})
}
return lines.Send(cmd, lr, lines.SenderOpts{Delimiter: []byte{'\n'}})
return lines.Send(cmd, lr, lines.SenderOpts{Delimiter: []byte{'\n'}, Limit: math.MaxInt32})
}
type searchFilesRequest interface {
......
This diff is collapsed.
......@@ -615,6 +615,65 @@ func (m *ObjectPool) GetRepository() *Repository {
return nil
}
type PaginationParameter struct {
// A page token allows for a generic token to be used for multiple
// definitions of the word 'page'. In the case of Git log, this would
// be the first commit identifier _after which_ to send the first
// result. For branches, this would be the name of the last branch known
// to the client.
PageToken string `protobuf:"bytes,1,opt,name=page_token,json=pageToken,proto3" json:"page_token,omitempty"`
// When fully consuming the response the client will receive _at most_
// `limit` number of resulting objects. Note that the number of response
// messages might be much lower, as some response messages already send
// multiple objects per message.
// When the limit is smaller than 0, it will be normalized to 2147483647
// on the server side. When limit is not set, it defaults to 0, and no
// results are send in the response.
Limit int32 `protobuf:"varint,2,opt,name=limit,proto3" json:"limit,omitempty"`
XXX_NoUnkeyedLiteral struct{} `json:"-"`
XXX_unrecognized []byte `json:"-"`
XXX_sizecache int32 `json:"-"`
}
func (m *PaginationParameter) Reset() { *m = PaginationParameter{} }
func (m *PaginationParameter) String() string { return proto.CompactTextString(m) }
func (*PaginationParameter) ProtoMessage() {}
func (*PaginationParameter) Descriptor() ([]byte, []int) {
return fileDescriptor_d8a4e87e678c5ced, []int{8}
}
func (m *PaginationParameter) XXX_Unmarshal(b []byte) error {
return xxx_messageInfo_PaginationParameter.Unmarshal(m, b)
}
func (m *PaginationParameter) XXX_Marshal(b []byte, deterministic bool) ([]byte, error) {
return xxx_messageInfo_PaginationParameter.Marshal(b, m, deterministic)
}
func (m *PaginationParameter) XXX_Merge(src proto.Message) {
xxx_messageInfo_PaginationParameter.Merge(m, src)
}
func (m *PaginationParameter) XXX_Size() int {
return xxx_messageInfo_PaginationParameter.Size(m)
}
func (m *PaginationParameter) XXX_DiscardUnknown() {
xxx_messageInfo_PaginationParameter.DiscardUnknown(m)
}
var xxx_messageInfo_PaginationParameter proto.InternalMessageInfo
func (m *PaginationParameter) GetPageToken() string {
if m != nil {
return m.PageToken
}
return ""
}
func (m *PaginationParameter) GetLimit() int32 {
if m != nil {
return m.Limit
}
return 0
}
func init() {
proto.RegisterEnum("gitaly.ObjectType", ObjectType_name, ObjectType_value)
proto.RegisterEnum("gitaly.SignatureType", SignatureType_name, SignatureType_value)
......@@ -626,60 +685,64 @@ func init() {
proto.RegisterType((*Tag)(nil), "gitaly.Tag")
proto.RegisterType((*User)(nil), "gitaly.User")
proto.RegisterType((*ObjectPool)(nil), "gitaly.ObjectPool")
proto.RegisterType((*PaginationParameter)(nil), "gitaly.PaginationParameter")
}
func init() { proto.RegisterFile("shared.proto", fileDescriptor_d8a4e87e678c5ced) }
var fileDescriptor_d8a4e87e678c5ced = []byte{
// 797 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x54, 0x5d, 0x6f, 0x23, 0x35,
0x14, 0xdd, 0x99, 0x4c, 0xbe, 0x6e, 0x26, 0x65, 0x30, 0x45, 0x1a, 0x15, 0xad, 0xb6, 0x0c, 0x12,
0xaa, 0x56, 0x65, 0x52, 0x05, 0x81, 0x40, 0xe2, 0xa5, 0x59, 0x4a, 0xd5, 0x85, 0x4d, 0xa2, 0x69,
0x2a, 0x10, 0x2f, 0x23, 0x27, 0xe3, 0x75, 0x8c, 0x3c, 0xf1, 0xc8, 0x76, 0x56, 0xa4, 0xcf, 0x3c,
0xf1, 0xc4, 0x9f, 0xe0, 0x95, 0x9f, 0xc1, 0xef, 0x42, 0xb6, 0x67, 0xb2, 0x59, 0x28, 0x88, 0x7d,
0xbb, 0xf7, 0xfa, 0xf8, 0xfa, 0xdc, 0xe3, 0x63, 0x43, 0xa8, 0xd6, 0x58, 0x92, 0x22, 0xad, 0xa4,
0xd0, 0x02, 0x75, 0x28, 0xd3, 0x98, 0xef, 0x4e, 0x9e, 0x50, 0x21, 0x28, 0x27, 0x23, 0x5b, 0x5d,
0x6e, 0x5f, 0x8e, 0x34, 0x2b, 0x89, 0xd2, 0xb8, 0xac, 0x1c, 0xf0, 0x04, 0x38, 0xdb, 0x68, 0x17,
0x27, 0x7f, 0xf8, 0x00, 0x19, 0xa9, 0x84, 0x62, 0x5a, 0xc8, 0x1d, 0xfa, 0x10, 0x42, 0xa5, 0x85,
0xc4, 0x94, 0xe4, 0x1b, 0x5c, 0x92, 0xd8, 0x3f, 0xf5, 0xce, 0xfa, 0xd9, 0xa0, 0xae, 0x4d, 0x71,
0x49, 0xd0, 0x47, 0x30, 0x94, 0x84, 0x63, 0xcd, 0x5e, 0x91, 0xbc, 0xc2, 0x7a, 0x1d, 0xb7, 0x2c,
0x26, 0x6c, 0x8a, 0x73, 0xac, 0xd7, 0xe8, 0x02, 0x8e, 0x29, 0xd3, 0xb9, 0x58, 0xfe, 0x44, 0x56,
0x3a, 0x2f, 0x98, 0x24, 0x2b, 0xd3, 0x3f, 0x0e, 0x2c, 0x16, 0x51, 0xa6, 0x67, 0x76, 0xe9, 0xeb,
0x66, 0x05, 0x5d, 0xc3, 0xa9, 0xd9, 0x81, 0xb9, 0x26, 0x72, 0x83, 0x35, 0xf9, 0xfb, 0x5e, 0x46,
0x54, 0xdc, 0x3e, 0x6d, 0x9d, 0xf5, 0xb3, 0xc7, 0x94, 0xe9, 0xcb, 0x06, 0xf6, 0x66, 0x1b, 0x46,
0x94, 0xe1, 0x47, 0x79, 0x2e, 0xf7, 0x33, 0xc5, 0x1d, 0xc7, 0x8f, 0xf2, 0x83, 0x39, 0x3f, 0x86,
0x77, 0x28, 0xcf, 0x2b, 0x29, 0xec, 0x19, 0x76, 0x8c, 0x9e, 0x85, 0x0d, 0x29, 0x9f, 0xbb, 0xaa,
0x99, 0xe3, 0x79, 0xd0, 0xf3, 0x22, 0xff, 0x79, 0xd0, 0xeb, 0x46, 0xbd, 0x2c, 0x30, 0xb0, 0xe4,
0x77, 0x1f, 0xfa, 0xd7, 0x4c, 0x3f, 0x13, 0x65, 0xc9, 0x34, 0x3a, 0x02, 0x9f, 0x15, 0xb1, 0x67,
0xb7, 0xfa, 0xac, 0x40, 0x31, 0x74, 0xd5, 0xd6, 0x52, 0xb2, 0xd2, 0x85, 0x59, 0x93, 0x22, 0x04,
0xc1, 0x52, 0x14, 0x3b, 0xab, 0x56, 0x98, 0xd9, 0x18, 0x9d, 0x43, 0x07, 0x6f, 0xf5, 0x5a, 0x48,
0xab, 0xcb, 0x60, 0x7c, 0x9c, 0xba, 0x2b, 0x4c, 0x5d, 0xf7, 0x4b, 0xbb, 0x96, 0xd5, 0x18, 0x34,
0x86, 0xfe, 0xca, 0xd6, 0x35, 0x91, 0x71, 0xfb, 0x3f, 0x36, 0xbc, 0x86, 0xa1, 0xc7, 0x00, 0x15,
0x96, 0x64, 0xa3, 0x73, 0x56, 0xa8, 0xb8, 0x63, 0xf5, 0xeb, 0xbb, 0xca, 0x4d, 0xa1, 0xd0, 0x07,
0xd0, 0x37, 0x44, 0x72, 0xc5, 0xee, 0x49, 0xdc, 0x3d, 0xf5, 0xce, 0x5a, 0x59, 0xcf, 0x14, 0x6e,
0xd9, 0x3d, 0x41, 0x5f, 0xc1, 0x91, 0x62, 0x74, 0x83, 0xf5, 0x56, 0x92, 0x5c, 0xef, 0x2a, 0x62,
0x25, 0x3a, 0x1a, 0xbf, 0xdf, 0x1c, 0x7a, 0xdb, 0xac, 0x2e, 0x76, 0x15, 0xc9, 0x86, 0xea, 0x30,
0x4d, 0x7e, 0xf1, 0x20, 0x3c, 0x64, 0x65, 0x04, 0xb0, 0x96, 0xf2, 0x9c, 0x00, 0x26, 0x46, 0xc7,
0xd0, 0x26, 0x25, 0x66, 0xbc, 0x16, 0xcb, 0x25, 0x28, 0x85, 0xa0, 0xc0, 0x9a, 0x58, 0xa9, 0x06,
0xe3, 0x93, 0xd4, 0xf9, 0x39, 0x6d, 0xfc, 0x9c, 0x2e, 0x1a, 0x3f, 0x67, 0x16, 0x87, 0x4e, 0xa0,
0x67, 0x2c, 0x7e, 0x2f, 0x36, 0xc4, 0x0a, 0x19, 0x66, 0xfb, 0x3c, 0x49, 0x00, 0xae, 0x7e, 0x66,
0xfa, 0x56, 0x63, 0xbd, 0x55, 0xe6, 0xbc, 0x57, 0x98, 0x6f, 0x1d, 0x89, 0x76, 0xe6, 0x92, 0x64,
0x01, 0x9d, 0x89, 0xc4, 0x9b, 0xd5, 0xfa, 0x41, 0x8e, 0x9f, 0xc3, 0x50, 0x63, 0x49, 0x89, 0xce,
0x9d, 0xac, 0x96, 0xeb, 0x60, 0xfc, 0x6e, 0xa3, 0xc2, 0xde, 0x0c, 0x59, 0xe8, 0x70, 0x2e, 0x4b,
0x7e, 0xf5, 0xa1, 0xb5, 0xc0, 0xf4, 0xc1, 0x9e, 0xce, 0x36, 0xfe, 0xde, 0x36, 0xff, 0x38, 0xa3,
0xf5, 0xbf, 0xce, 0x30, 0x76, 0x2b, 0x89, 0x52, 0x98, 0x36, 0x83, 0x37, 0xa9, 0x79, 0xc8, 0x75,
0xe8, 0x2e, 0xb7, 0x6d, 0x2f, 0x77, 0x50, 0xd7, 0xec, 0xfd, 0x9e, 0x43, 0x47, 0x63, 0x4a, 0x89,
0xb4, 0x2f, 0xe4, 0x5f, 0xdd, 0xe7, 0x30, 0x0f, 0xb8, 0xa1, 0xfb, 0x16, 0x6e, 0x78, 0x09, 0xc1,
0x9d, 0x22, 0x12, 0xbd, 0x07, 0x6d, 0xca, 0xf3, 0xfd, 0x93, 0x09, 0x28, 0xbf, 0x29, 0xf6, 0x0a,
0xf9, 0x0f, 0x39, 0xa3, 0x75, 0xe8, 0x8c, 0x27, 0x30, 0xa0, 0x3c, 0xdf, 0x2a, 0xf3, 0xf6, 0x4b,
0x52, 0xff, 0x26, 0x40, 0xf9, 0x5d, 0x5d, 0x49, 0xbe, 0x01, 0x70, 0x3f, 0xc2, 0x5c, 0x08, 0x8e,
0xbe, 0x00, 0x38, 0xf8, 0x07, 0x3c, 0x3b, 0x25, 0x6a, 0xf8, 0xbe, 0xfe, 0x0d, 0x26, 0xc1, 0x6f,
0x7f, 0x9e, 0x7b, 0xd9, 0x01, 0xf6, 0xe9, 0xa4, 0xe9, 0x63, 0xd8, 0xa3, 0x01, 0x74, 0xef, 0xa6,
0xdf, 0x4e, 0x67, 0xdf, 0x4f, 0xa3, 0x47, 0x08, 0xa0, 0xf3, 0x6c, 0xf6, 0xe2, 0xc5, 0xcd, 0x22,
0xf2, 0x50, 0x0f, 0x82, 0xc9, 0x77, 0xb3, 0x49, 0xe4, 0x9b, 0x68, 0x91, 0x5d, 0x5d, 0x45, 0x2d,
0xd4, 0x85, 0xd6, 0xe2, 0xf2, 0x3a, 0x0a, 0x9e, 0x9e, 0xc3, 0xf0, 0x0d, 0x4d, 0x0c, 0x66, 0x3a,
0x9b, 0x5e, 0x45, 0x8f, 0x0c, 0x66, 0x7e, 0x3d, 0x77, 0x0d, 0x7e, 0xf8, 0xec, 0xe2, 0xcb, 0xc8,
0x9f, 0x5c, 0xfc, 0x68, 0x88, 0x71, 0xbc, 0x4c, 0x57, 0xa2, 0x1c, 0xb9, 0xf0, 0x13, 0x21, 0xe9,
0xc8, 0xd1, 0x75, 0xbf, 0xf9, 0x88, 0x8a, 0x3a, 0xaf, 0x96, 0xcb, 0x8e, 0x2d, 0x7d, 0xfa, 0x57,
0x00, 0x00, 0x00, 0xff, 0xff, 0x11, 0x19, 0x40, 0xb8, 0x06, 0x06, 0x00, 0x00,
// 835 bytes of a gzipped FileDescriptorProto
0x1f, 0x8b, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0xff, 0x94, 0x55, 0x4f, 0x8f, 0xe3, 0x34,
0x1c, 0xdd, 0xa4, 0xe9, 0xbf, 0x5f, 0xdb, 0x21, 0x78, 0x07, 0x29, 0x1a, 0xb4, 0xda, 0x21, 0x48,
0x68, 0xb4, 0x1a, 0xda, 0x51, 0x11, 0x08, 0x24, 0x2e, 0xd3, 0x65, 0x18, 0xcd, 0xc0, 0xb6, 0x55,
0xa6, 0x23, 0x10, 0x97, 0xc8, 0x6d, 0xbc, 0xae, 0xc1, 0x89, 0x23, 0xdb, 0x5d, 0xd1, 0x39, 0x73,
0xe2, 0xc4, 0x97, 0xe0, 0xca, 0xc7, 0xe0, 0x73, 0x21, 0xdb, 0x49, 0xb7, 0x0b, 0x05, 0xb1, 0x37,
0xff, 0x5e, 0x9e, 0xed, 0xf7, 0x7b, 0x7e, 0x76, 0xa0, 0xaf, 0xd6, 0x58, 0x92, 0x6c, 0x58, 0x4a,
0xa1, 0x05, 0x6a, 0x51, 0xa6, 0x31, 0xdf, 0x9e, 0x3c, 0xa5, 0x42, 0x50, 0x4e, 0x46, 0x16, 0x5d,
0x6e, 0x5e, 0x8e, 0x34, 0xcb, 0x89, 0xd2, 0x38, 0x2f, 0x1d, 0xf1, 0x04, 0x38, 0x2b, 0xb4, 0x1b,
0xc7, 0x7f, 0xf8, 0x00, 0x09, 0x29, 0x85, 0x62, 0x5a, 0xc8, 0x2d, 0xfa, 0x00, 0xfa, 0x4a, 0x0b,
0x89, 0x29, 0x49, 0x0b, 0x9c, 0x93, 0xc8, 0x3f, 0xf5, 0xce, 0xba, 0x49, 0xaf, 0xc2, 0xa6, 0x38,
0x27, 0xe8, 0x43, 0x18, 0x48, 0xc2, 0xb1, 0x66, 0xaf, 0x48, 0x5a, 0x62, 0xbd, 0x8e, 0x1a, 0x96,
0xd3, 0xaf, 0xc1, 0x39, 0xd6, 0x6b, 0x74, 0x01, 0xc7, 0x94, 0xe9, 0x54, 0x2c, 0x7f, 0x24, 0x2b,
0x9d, 0x66, 0x4c, 0x92, 0x95, 0x59, 0x3f, 0x0a, 0x2c, 0x17, 0x51, 0xa6, 0x67, 0xf6, 0xd3, 0x57,
0xf5, 0x17, 0x74, 0x0d, 0xa7, 0x66, 0x06, 0xe6, 0x9a, 0xc8, 0x02, 0x6b, 0xf2, 0xf7, 0xb9, 0x8c,
0xa8, 0xa8, 0x79, 0xda, 0x38, 0xeb, 0x26, 0x4f, 0x28, 0xd3, 0x97, 0x35, 0xed, 0xcd, 0x65, 0x18,
0x51, 0x46, 0x1f, 0xe5, 0xa9, 0xdc, 0xf5, 0x14, 0xb5, 0x9c, 0x3e, 0xca, 0xf7, 0xfa, 0xfc, 0x08,
0xde, 0xa1, 0x3c, 0x2d, 0xa5, 0xb0, 0x7b, 0xd8, 0x36, 0x3a, 0x96, 0x36, 0xa0, 0x7c, 0xee, 0x50,
0xd3, 0xc7, 0x6d, 0xd0, 0xf1, 0x42, 0xff, 0x36, 0xe8, 0xb4, 0xc3, 0x4e, 0x12, 0x18, 0x5a, 0xfc,
0xbb, 0x0f, 0xdd, 0x6b, 0xa6, 0x9f, 0x8b, 0x3c, 0x67, 0x1a, 0x1d, 0x81, 0xcf, 0xb2, 0xc8, 0xb3,
0x53, 0x7d, 0x96, 0xa1, 0x08, 0xda, 0x6a, 0x63, 0x25, 0x59, 0xeb, 0xfa, 0x49, 0x5d, 0x22, 0x04,
0xc1, 0x52, 0x64, 0x5b, 0xeb, 0x56, 0x3f, 0xb1, 0x63, 0x74, 0x0e, 0x2d, 0xbc, 0xd1, 0x6b, 0x21,
0xad, 0x2f, 0xbd, 0xf1, 0xf1, 0xd0, 0x1d, 0xe1, 0xd0, 0xad, 0x7e, 0x69, 0xbf, 0x25, 0x15, 0x07,
0x8d, 0xa1, 0xbb, 0xb2, 0xb8, 0x26, 0x32, 0x6a, 0xfe, 0xc7, 0x84, 0xd7, 0x34, 0xf4, 0x04, 0xa0,
0xc4, 0x92, 0x14, 0x3a, 0x65, 0x99, 0x8a, 0x5a, 0xd6, 0xbf, 0xae, 0x43, 0x6e, 0x32, 0x85, 0xde,
0x87, 0xae, 0x11, 0x92, 0x2a, 0xf6, 0x40, 0xa2, 0xf6, 0xa9, 0x77, 0xd6, 0x48, 0x3a, 0x06, 0xb8,
0x63, 0x0f, 0x04, 0x7d, 0x09, 0x47, 0x8a, 0xd1, 0x02, 0xeb, 0x8d, 0x24, 0xa9, 0xde, 0x96, 0xc4,
0x5a, 0x74, 0x34, 0x7e, 0xaf, 0xde, 0xf4, 0xae, 0xfe, 0xba, 0xd8, 0x96, 0x24, 0x19, 0xa8, 0xfd,
0x32, 0xfe, 0xc5, 0x83, 0xfe, 0xbe, 0x2a, 0x63, 0x80, 0x8d, 0x94, 0xe7, 0x0c, 0x30, 0x63, 0x74,
0x0c, 0x4d, 0x92, 0x63, 0xc6, 0x2b, 0xb3, 0x5c, 0x81, 0x86, 0x10, 0x64, 0x58, 0x13, 0x6b, 0x55,
0x6f, 0x7c, 0x32, 0x74, 0x79, 0x1e, 0xd6, 0x79, 0x1e, 0x2e, 0xea, 0x3c, 0x27, 0x96, 0x87, 0x4e,
0xa0, 0x63, 0x22, 0xfe, 0x20, 0x0a, 0x62, 0x8d, 0xec, 0x27, 0xbb, 0x3a, 0x8e, 0x01, 0xae, 0x7e,
0x66, 0xfa, 0x4e, 0x63, 0xbd, 0x51, 0x66, 0xbf, 0x57, 0x98, 0x6f, 0x9c, 0x88, 0x66, 0xe2, 0x8a,
0x78, 0x01, 0xad, 0x89, 0xc4, 0xc5, 0x6a, 0x7d, 0x50, 0xe3, 0x67, 0x30, 0xd0, 0x58, 0x52, 0xa2,
0x53, 0x67, 0xab, 0xd5, 0xda, 0x1b, 0xbf, 0x5b, 0xbb, 0xb0, 0x0b, 0x43, 0xd2, 0x77, 0x3c, 0x57,
0xc5, 0xbf, 0xfa, 0xd0, 0x58, 0x60, 0x7a, 0x70, 0x4d, 0x17, 0x1b, 0x7f, 0x17, 0x9b, 0x7f, 0xec,
0xd1, 0xf8, 0x5f, 0x7b, 0x98, 0xb8, 0xe5, 0x44, 0x29, 0x4c, 0xeb, 0xc6, 0xeb, 0xd2, 0x5c, 0xe4,
0x6a, 0xe8, 0x0e, 0xb7, 0x69, 0x0f, 0xb7, 0x57, 0x61, 0xf6, 0x7c, 0xcf, 0xa1, 0xa5, 0x31, 0xa5,
0x44, 0xda, 0x1b, 0xf2, 0xaf, 0xe9, 0x73, 0x9c, 0x03, 0x69, 0x68, 0xbf, 0x45, 0x1a, 0x5e, 0x42,
0x70, 0xaf, 0x88, 0x44, 0x8f, 0xa1, 0x49, 0x79, 0xba, 0xbb, 0x32, 0x01, 0xe5, 0x37, 0xd9, 0xce,
0x21, 0xff, 0x50, 0x32, 0x1a, 0xfb, 0xc9, 0x78, 0x0a, 0x3d, 0xca, 0xd3, 0x8d, 0x32, 0x77, 0x3f,
0x27, 0xd5, 0x6b, 0x02, 0x94, 0xdf, 0x57, 0x48, 0xfc, 0x35, 0x80, 0x7b, 0x11, 0xe6, 0x42, 0x70,
0xf4, 0x39, 0xc0, 0xde, 0x3b, 0xe0, 0xd9, 0x2e, 0x51, 0xad, 0xf7, 0xf5, 0x6b, 0x30, 0x09, 0x7e,
0xfb, 0xf3, 0xdc, 0x4b, 0xf6, 0xb8, 0xf1, 0x2d, 0x3c, 0x9e, 0x63, 0xca, 0x0a, 0xac, 0x99, 0x28,
0xe6, 0x58, 0xe2, 0x9c, 0xec, 0xae, 0x13, 0x25, 0xa9, 0x16, 0x3f, 0x91, 0xa2, 0xea, 0xa1, 0x6b,
0x90, 0x85, 0x01, 0x8c, 0x68, 0xce, 0xea, 0x88, 0x34, 0x13, 0x57, 0x3c, 0x9b, 0xd4, 0x9a, 0x8c,
0x13, 0xa8, 0x07, 0xed, 0xfb, 0xe9, 0x37, 0xd3, 0xd9, 0x77, 0xd3, 0xf0, 0x11, 0x02, 0x68, 0x3d,
0x9f, 0xbd, 0x78, 0x71, 0xb3, 0x08, 0x3d, 0xd4, 0x81, 0x60, 0xf2, 0xed, 0x6c, 0x12, 0xfa, 0x66,
0xb4, 0x48, 0xae, 0xae, 0xc2, 0x06, 0x6a, 0x43, 0x63, 0x71, 0x79, 0x1d, 0x06, 0xcf, 0xce, 0x61,
0xf0, 0x86, 0xbf, 0x86, 0x33, 0x9d, 0x4d, 0xaf, 0xc2, 0x47, 0x86, 0x33, 0xbf, 0x9e, 0xbb, 0x05,
0xbe, 0xff, 0xf4, 0xe2, 0x8b, 0xd0, 0x9f, 0x5c, 0xfc, 0x60, 0x9a, 0xe4, 0x78, 0x39, 0x5c, 0x89,
0x7c, 0xe4, 0x86, 0x1f, 0x0b, 0x49, 0x47, 0xae, 0x75, 0xf7, 0x67, 0x18, 0x51, 0x51, 0xd5, 0xe5,
0x72, 0xd9, 0xb2, 0xd0, 0x27, 0x7f, 0x05, 0x00, 0x00, 0xff, 0xff, 0x7d, 0xe3, 0xe3, 0xc9, 0x52,
0x06, 0x00, 0x00,
}
......@@ -167,6 +167,11 @@ message FindLocalBranchesRequest {
UPDATED_DESC = 2;
}
SortBy sort_by = 2;
// The page token is the branch name, with the `refs/heads/` prefix, for
// example "refs/heads/master". After the first branch name is encountered
// which lexicographically exceeds the page token, it will be the first result
// send as part of the response.
PaginationParameter pagination_params = 3;
}
message FindLocalBranchesResponse {
......
......@@ -103,3 +103,20 @@ message User {
message ObjectPool {
Repository repository = 1 [(gitaly.repository)=true];
}
message PaginationParameter {
// A page token allows for a generic token to be used for multiple
// definitions of the word 'page'. In the case of Git log, this would
// be the first commit identifier _after which_ to send the first
// result. For branches, this would be the name of the last branch known
// to the client.
string page_token = 1;
// When fully consuming the response the client will receive _at most_
// `limit` number of resulting objects. Note that the number of response
// messages might be much lower, as some response messages already send
// multiple objects per message.
// When the limit is smaller than 0, it will be normalized to 2147483647
// on the server side. When limit is not set, it defaults to 0, and no
// results are send in the response.
int32 limit = 2;
}
......@@ -45,6 +45,7 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "gitaly.FindLocalBranchesRequest" do
optional :repository, :message, 1, "gitaly.Repository"
optional :sort_by, :enum, 2, "gitaly.FindLocalBranchesRequest.SortBy"
optional :pagination_params, :message, 3, "gitaly.PaginationParameter"
end
add_enum "gitaly.FindLocalBranchesRequest.SortBy" do
value :NAME, 0
......
......@@ -55,6 +55,10 @@ Google::Protobuf::DescriptorPool.generated_pool.build do
add_message "gitaly.ObjectPool" do
optional :repository, :message, 1, "gitaly.Repository"
end
add_message "gitaly.PaginationParameter" do
optional :page_token, :string, 1
optional :limit, :int32, 2
end
add_enum "gitaly.ObjectType" do
value :UNKNOWN, 0
value :COMMIT, 1
......@@ -78,6 +82,7 @@ module Gitaly
Tag = Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.Tag").msgclass
User = Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.User").msgclass
ObjectPool = Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.ObjectPool").msgclass
PaginationParameter = Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.PaginationParameter").msgclass
ObjectType = Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.ObjectType").enummodule
SignatureType = Google::Protobuf::DescriptorPool.generated_pool.lookup("gitaly.SignatureType").enummodule
end
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment