-
Notifications
You must be signed in to change notification settings - Fork 691
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ISSUE-4234 Add pagination to Get Tenants endpoint #5027
base: main
Are you sure you want to change the base?
ISSUE-4234 Add pagination to Get Tenants endpoint #5027
Conversation
2d3bc9e
to
3555249
Compare
3555249
to
3d0cbba
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is looking really good and coming along nicely, thanks for doing this work! I know this PR might not be ready for an "official" review yet, but I wanted to leave some comments now with the hope that they'll be helpful. Many of these are "nit's" which you're welcome to do or ignore, however some of the comments are important. Happy to discuss anything in more detail of course
@@ -274,7 +274,7 @@ func (s *schemaHandlers) deleteTenants(params schema.TenantsDeleteParams, | |||
func (s *schemaHandlers) getTenants(params schema.TenantsGetParams, | |||
principal *models.Principal, | |||
) middleware.Responder { | |||
tenants, err := s.manager.GetConsistentTenants(params.HTTPRequest.Context(), principal, params.ClassName, *params.Consistency, nil) | |||
tenants, err := s.manager.GetConsistentTenants(params.HTTPRequest.Context(), principal, params.ClassName, *params.Consistency, nil, nil, nil) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
tenants, err := s.manager.GetConsistentTenants(params.HTTPRequest.Context(), principal, params.ClassName, *params.Consistency, nil, nil, nil) | |
tenants, err := s.manager.GetConsistentTenants(params.HTTPRequest.Context(), principal, params.ClassName, *params.Consistency, nil, params.After, params.Limit) |
cluster/utils/priorityqueue/queue.go
Outdated
more func(items []string, i, j int) bool | ||
} | ||
|
||
// NewMaxStringPriorityQueue constructs a priority queue with more. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
// NewMaxStringPriorityQueue constructs a priority queue with more. | |
// NewMaxStringPriorityQueue constructs a priority queue with the specified initial capacity (initial length is always 0). |
cluster/store/schema.go
Outdated
// TODO only one of these checks? | ||
for pq.Len() > 0 && resIndex < len(res) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
// TODO only one of these checks? | |
for pq.Len() > 0 && resIndex < len(res) { | |
for pq.Len() > 0 { |
cluster/store/schema.go
Outdated
for i, j := 0, len(res)-1; i < j; i, j = i+1, j-1 { | ||
res[i], res[j] = res[j], res[i] | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
for i, j := 0, len(res)-1; i < j; i, j = i+1, j-1 { | |
res[i], res[j] = res[j], res[i] | |
} | |
slices.Reverse(res) |
cluster/store/schema.go
Outdated
return res | ||
} | ||
|
||
func (s *schema) getTenants(class string, tenants []string, after *string, limit *int64) ([]*models.Tenant, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit, I'm concerned that having after
and limit
as pointers here makes the code below less legible and increase the potential for future changes to inadvertently introduce nil pointer issues. I'd love to hear your thoughts on whether you think it would be better to convert the pointers to basic types (eg use default values if nil) before calling this function or not? Not sure exactly how "high" up the stack we should push this conversion if we want to avoid passing pointers down this far.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me think about this a bit more, but to clarify you are just asking if I think it it could be better to handle the nil values of these pointers (and using default/zero value if they are nil) up the stack?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hey @nathanwilk7 just curious if you saw my clarifying question above.
usecases/schema/fakes_test.go
Outdated
if args.Get(0) == nil { | ||
return nil, 0, args.Error(2) | ||
} | ||
return args.Get(0).([]*models.Tenant), args.Get(1).(uint64), args.Error(2) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit
if args.Get(0) == nil { | |
return nil, 0, args.Error(2) | |
} | |
return args.Get(0).([]*models.Tenant), args.Get(1).(uint64), args.Error(2) | |
tenant := args.Get(0) | |
if tenant == nil { | |
return nil, 0, args.Error(2) | |
} | |
shardVersion := args.Get(1) | |
return tenant.([]*models.Tenant), shardVersion.(uint64), args.Error(2) |
usecases/schema/tenant.go
Outdated
@@ -169,45 +172,60 @@ func (h *Handler) DeleteTenants(ctx context.Context, principal *models.Principal | |||
// GetTenants is used to get tenants of a class. | |||
// | |||
// Class must exist and has partitioning enabled | |||
func (h *Handler) GetTenants(ctx context.Context, principal *models.Principal, class string) ([]*models.Tenant, error) { | |||
func (h *Handler) GetTenants(ctx context.Context, principal *models.Principal, class string, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this func is currently unused can you confirm that is correct on both this branch and main and if so, delete it and delete the getTenants
function in this same file below?
usecases/schema/tenant.go
Outdated
ts = make([]*models.Tenant, n) | ||
} else if n < len(ts) { | ||
ts = ts[:n] | ||
if after != nil && limit != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This code is similar to the cluster/store/schema.go:getTenants
, can it be changed to avoid duplicating the logic (eg "DRY'd up"?)
@@ -260,24 +280,72 @@ func IsLocalActiveTenant(phys *sharding.Physical, localNode string) bool { | |||
phys.Status == models.TenantActivityStatusHOT | |||
} | |||
|
|||
func (h *Handler) getTenantsByNames(class string, names []string) ([]*models.Tenant, error) { | |||
func (h *Handler) getTenantsByNames(class string, names []string, after *string, limit *int64) ([]*models.Tenant, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reminder we may want to revisit this once we've decided on how the API should work for all parameter combintations
usecases/schema/tenant.go
Outdated
} | ||
} | ||
|
||
func getAllTenantsPriorityQueue(shards map[string]sharding.Physical, after string, limit int) []*models.Tenant { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks to me like essentially (exactly?) the same function as the one in cluster/store/schema.go
, can we avoid duplicating this logic?
I also just noticed that while I was reviewing you pushed some changes (crazy timing!). If any of my comments don't apply after the recent commit, just let me know |
Hey @nathanwilk7 sorry for the late reply. Been super busy and only just now saw your comments. I'll try and get to at least some of them today or tomorrow at the latest, so we can push this PR forward. Thank you for helping out!!! cheers |
dfc33c7
to
5898f5f
Compare
|
hey @nathanwilk7 FYI, I made a handful of changes. As you noted before, we should get the expected API behavior hashed, which will also help me adjust some of my now failing tests given the existing random order if |
@@ -292,7 +292,7 @@ func (s *schemaHandlers) getTenants(params schema.TenantsGetParams, | |||
} | |||
|
|||
func (s *schemaHandlers) tenantExists(params schema.TenantExistsParams, principal *models.Principal) middleware.Responder { | |||
if err := s.manager.ConsistentTenantExists(params.HTTPRequest.Context(), principal, params.ClassName, *params.Consistency, params.TenantName); err != nil { | |||
if err := s.manager.ConsistentTenantExists(params.HTTPRequest.Context(), principal, params.ClassName, *params.Consistency, params.TenantName, nil, nil); err != nil { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@nathanwilk7 this should probably change as well. Currently it's using the same function just see if a tenant exists; it gets the full list of tenants and then checks. That's why I just left after and limit nil here since they are technically not needed. However, that's probably a sign this function needs to change. Should I do that as part of this PR or push it to another PR after to handle after this one?
cluster/store/schema.go
Outdated
return res | ||
} | ||
|
||
func (s *schema) getTenants(class string, tenants []string, after *string, limit *int64) ([]*models.Tenant, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
let me think about this a bit more, but to clarify you are just asking if I think it it could be better to handle the nil values of these pointers (and using default/zero value if they are nil) up the stack?
cluster/store/schema.go
Outdated
return nil | ||
} | ||
return res, meta.RLockGuard(f) | ||
} | ||
|
||
func CappedTenants(limit *int64, res []*models.Tenant, tenants []string, ss *sharding.State) []*models.Tenant { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This name is terrible and needs to probably be changed, but it's late and I drew a blank lol. Help with variable names always accepted 🫶
cluster/store/schema.go
Outdated
return res | ||
} | ||
|
||
func (s *schema) getTenants(class string, tenants []string, after *string, limit *int64) ([]*models.Tenant, error) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
hey @nathanwilk7 just curious if you saw my clarifying question above.
cluster/store/schema.go
Outdated
} | ||
|
||
if limit != nil { | ||
res = make([]*models.Tenant, 0, *limit) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hey @nathanwilk7 and @tsmith023 sorry for the bother, but just curious if Tommy saw Nathan and I's comments. I wanted to avoid proceeding too much since I don't think it's my place to make API design decisions at this point.
Updated GetConsistentTenants endpoint with `after` and `limit` vars in order to implement pagination for th endpoint. This required refactoring the following: the implementation of QueryTenantRequest by adding the `after` and `limit` vars. Also, the implementation of getTenants (original handler.getTenant and cluster/store schema .getTenants) method with the addition of `after` and `limit` vars which included the addition of implementation of pagination in its code definition. Note, we created priority queue package to represent a max-heap of string items. This is used to implement pagination. `after` is the tenant for which GET of tenants will be AFTER. `limit` is the limit of tenants we GET. Added test for GetConsistenTenants endpoint. Added additional test case for QueryTenants test case in cluster store test for TestServiceEndpoints to ensure after and limit worked correctly with the cluster store as well.
5898f5f
to
6856272
Compare
Updated GetConsistentTenants endpoint with
after
andlimit
vars in order to implement pagination for th endpoint. This required refactoring the following: the implementation of QueryTenantRequest by adding theafter
andlimit
vars. Also, the implementation of getTenants (original handler.getTenant and cluster/store schema .getTenants) method with the addition ofafter
andlimit
vars which included the addition of implementation of pagination in its code definition.Note, we created priority queue package to represent a max-heap of string items. This is used to implement pagination.
after
is the tenant for which GET of tenants will be after.limit
is the limit of tenants we GET.Added test for GetConsistenTenants endpoint.
Added additional test case for QueryTenants test case in cluster store test for TestServiceEndpoints to ensure after and limit worked correctly with the cluster store as well.