CBG-5327: Wire up REST API to document channel history compaction#8275
CBG-5327: Wire up REST API to document channel history compaction#8275RIT3shSapata wants to merge 11 commits into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR wires document channel history compaction into the Admin REST API and adds a REST-accessible way to inspect a document’s channel revocation history.
Changes:
- Added Admin REST routes and handlers for getting document channel history and compacting channel history.
- Added
GetDocChannelHistoryplus updated compaction output to deduplicate compacted channel names. - Added REST/API tests and updated OpenAPI path documentation.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 7 comments.
Show a summary per file
| File | Description |
|---|---|
rest/routing.go |
Registers new Admin channel history GET and compaction POST routes. |
rest/doc_api.go |
Adds request/response handling for channel history APIs. |
rest/api_test.go |
Adds REST coverage and updates compaction expectations for deduplicated channels. |
docs/api/paths/admin/keyspace-_history.yaml |
Updates documented GET channel history response schema. |
docs/api/paths/admin/keyspace-_history-compact.yaml |
Updates compaction response description. |
db/crud.go |
Adds channel history retrieval and deduplicates compacted channel results. |
Comments suppressed due to low confidence (2)
docs/api/paths/admin/keyspace-_history.yaml:17
- This description conflicts with the implemented behavior and the new test for a channel that is revoked and then re-added: such a channel is still returned because it has revocation history. Rephrase this to say active channel memberships without any revocation history are not included, rather than implying all currently assigned channels are excluded.
names to the sequences at which the document was removed from each channel. Only channels
that have been revoked at least once are included; channels the document is currently
assigned to are excluded.
docs/api/paths/admin/keyspace-_history.yaml:34
- This map response is missing the repository’s OpenAPI convention of naming additionalProperties keys with
x-additionalPropertiesName(for example,docs/api/paths/admin/keyspace-_history-compact.yaml:59-61uses it for doc IDs). Add an appropriate key name such aschannel_nameto keep generated docs consistent.
additionalProperties:
type: array
| '/{keyspace}/_channel_history/{docid}': | ||
| $ref: './paths/admin/keyspace-_history.yaml' | ||
| '/{keyspace}/_history/compact': | ||
| '/{keyspace}/_channel_history/compact': |
| if err != nil && !base.IsDocNotFoundError(err) { | ||
| return err |
| additionalProperties: | ||
| type: array | ||
| items: | ||
| type: integer | ||
| format: int64 | ||
| minimum: 0 | ||
| description: Sequences at which the document was removed from this channel. |
| func (h *handler) handleGetDocChannelHistory() error { | ||
| h.assertAdminOnly() | ||
|
|
||
| if !h.collection.UseXattrs() { | ||
| return fmt.Errorf("xattrs not enabled") | ||
| } |
adamcfraser
left a comment
There was a problem hiding this comment.
Posted text cleanup from our discussion - final review pending decisions on discussion items.
- added route for get request and the handler - created a get channel history function and added test coverage
- add route and handler to handle http request - add test coverage for http request - use set instead of array to store compacted channels
- add docstrings to all functions - updated api spec
- add request validation - fix docstrings
This reverts commit f797210.
- changed the endpoint for GET and POST requests - changed the request body and response for POST request - changed the resposne for the GET request - updated the OPEN API spec
- renamed the api path fixes - changed the response of the get request to include multiple sequences - updated the docstrings and the open api spec - fixed the permission issue in the route - handle not found error in the rest handler
Redocly previews |
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 8 out of 8 changed files in this pull request and generated 8 comments.
Comments suppressed due to low confidence (4)
docs/api/paths/admin/keyspace-_channel_history-compact.yaml:56
- The documented 200 response schema doesn’t match the actual handler output. The code returns an object with a
compacted_channelsproperty (array of strings), but this spec currently describes an object withadditionalProperties(and an unrelatedx-additionalPropertiesName: doc_id). Update the schema to definecompacted_channelsas a property and remove theadditionalPropertiesmapping.
docs/api/paths/admin/keyspace-_channel_history-compact.yaml:37 - The request schema allows
seqwithminimum: 0, but the handler currently returns 400 whenseq==0. Either allow0(treat as a valid no-op) or update the OpenAPI schema/description to requireseq >= 1so the contract matches runtime behavior.
docs/api/paths/admin/keyspace-_channel_history-compact.yaml:59 - The description has a grammar typo: “A array of all the compacted channels” should be “An array of all the compacted channels”.
docs/api/paths/admin/keyspace-_channel_history-compact.yaml:67 operationIdin this file still references the old_historyendpoint name (post_keyspace-_history-compact), but the path is now/_channel_history/{docid}/compact. Update the operationId to match the new endpoint naming to avoid collisions/confusion in generated clients.
| err := h.readJSONInto(&req) | ||
| if err != nil { | ||
| return base.HTTPErrorf(http.StatusBadRequest, "invalid JSON: %v", err) | ||
| } | ||
|
|
||
| if req.Seq == 0 { | ||
| return base.HTTPErrorf(http.StatusBadRequest, "missing seq") | ||
| } |
There was a problem hiding this comment.
changing the open api spec
| } | ||
| _, err = c.dataStore.UpdateXattrs(ctx, key, 0, cas, updatedXattr, opts) | ||
| return compactedChannels, err | ||
| return compactedChannels.ToArray(), err |
| schema: | ||
| type: object | ||
| additionalProperties: | ||
| type: array | ||
| items: | ||
| type: integer | ||
| format: int64 | ||
| minimum: 0 | ||
| description: Sequences at which the document was removed from this channel. | ||
| description: Map of channel names to their revocation sequences. |
| response[chanName] = make([]uint64, 0) | ||
| for seq, _ := range chanEntry { | ||
| response[chanName] = append(response[chanName], seq) | ||
| } |
There was a problem hiding this comment.
I agree with co-pilot that the individual slices need to be sorted by value.
I would go further, and suggest that the list of channels in the response map should also be sorted by sequence (or sequence[0]), so that callers can easily find the sequence they want to use for the POST operation.
e.g. with this:
"channel1": [10, 4],
"channel2:": [5, 2],
"channel3": [12],
"channel4": [7]
it's harder to see which channels will be compacted for a given sequence value
I think it would be preferable to return sorted by first sequence:
"channel3": [12],
"channel1": [10, 4],
"channel4": [7],
"channel2:": [5, 2]
What do you think?
adamcfraser
left a comment
There was a problem hiding this comment.
Generally looks good, one naming suggestion and then some comments about response ordering.
| response[chanName] = make([]uint64, 0) | ||
| for seq, _ := range chanEntry { | ||
| response[chanName] = append(response[chanName], seq) | ||
| } |
There was a problem hiding this comment.
I agree with co-pilot that the individual slices need to be sorted by value.
I would go further, and suggest that the list of channels in the response map should also be sorted by sequence (or sequence[0]), so that callers can easily find the sequence they want to use for the POST operation.
e.g. with this:
"channel1": [10, 4],
"channel2:": [5, 2],
"channel3": [12],
"channel4": [7]
it's harder to see which channels will be compacted for a given sequence value
I think it would be preferable to return sorted by first sequence:
"channel3": [12],
"channel1": [10, 4],
"channel4": [7],
"channel2:": [5, 2]
What do you think?
|
|
||
| } | ||
|
|
||
| type ChannelHistory map[string]map[uint64]bool |
There was a problem hiding this comment.
In cases where we're just using a map to store unique keys and don't care about the value, I prefer using empty struct:
| type ChannelHistory map[string]map[uint64]bool | |
| type ChannelHistory map[string]map[uint64]struct{} |
This has some memory savings (which we don't really care about here), but also makes it self-documenting that we don't care about the map value.
| } | ||
| } | ||
|
|
||
| func (ch ChannelHistory) getChannelHistoryResponse() map[string][]uint64 { |
There was a problem hiding this comment.
Since this is in the db package, it's better to avoid naming like 'Response', since that implies REST functionality. Maybe just asMap() or asSequenceSlices()?
CBG-5327
Describe your PR here...
Pre-review checklist
fmt.Print,log.Print, ...)base.UD(docID),base.MD(dbName))docs/apiDependencies (if applicable)
Upstream PR: CBG-5326: Function to handle document channel history compaction #8218Integration Tests