Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 63 additions & 5 deletions db/crud.go
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,62 @@ func (c *DatabaseCollection) GetDocSyncData(ctx context.Context, docid string) (

}

type ChannelHistory map[string]map[uint64]struct{}

func (ch ChannelHistory) addChannelHistoryEntry(name string, seq uint64) {
if _, ok := ch[name]; !ok {
ch[name] = make(map[uint64]struct{})
}
if _, ok := ch[name][seq]; !ok {
ch[name][seq] = struct{}{}
}
}

func (ch ChannelHistory) getChannelHistoryAsMap() map[string][]uint64 {
response := make(map[string][]uint64)
for chanName, chanEntry := range ch {
response[chanName] = make([]uint64, 0)
for seq, _ := range chanEntry {
response[chanName] = append(response[chanName], seq)
}
slices.Sort(response[chanName])
slices.Reverse(response[chanName])
}
return response
}

// GetDocChannelHistory returns the channel revocation history for the given document as a map
// from channel name to the sequences at which the document was removed from that channel.
// It collects revocation sequences from the active Channels map, the ChannelSet, and the
// ChannelSetHistory (overflow). Only channels that have been revoked at least once appear in
// the result; active memberships with no revocation history are omitted, even though a currently
// assigned channel can still appear if it was revoked and later re-added.
Comment thread
RIT3shSapata marked this conversation as resolved.
func (c *DatabaseCollection) GetDocChannelHistory(ctx context.Context, docid string) (map[string][]uint64, error) {

chanHistory := make(ChannelHistory)
syncData, err := c.GetDocSyncData(ctx, docid)
if err != nil {
return nil, err
}
for chanName, chanVal := range syncData.Channels {
if chanVal != nil && chanVal.Seq != 0 {
chanHistory.addChannelHistoryEntry(chanName, chanVal.Seq)
}
}
for _, chanSetEntry := range syncData.ChannelSet {
if chanSetEntry.End != 0 {
chanHistory.addChannelHistoryEntry(chanSetEntry.Name, chanSetEntry.End)
}
}
for _, chanSetEntry := range syncData.ChannelSetHistory {
if chanSetEntry.End != 0 {
chanHistory.addChannelHistoryEntry(chanSetEntry.Name, chanSetEntry.End)
}
}

return chanHistory.getChannelHistoryAsMap(), nil
}

// CompactDocChannelHistory removes channel history entries that ended at or before the given sequence number.
// This is used to prune stale channel assignment history to reduce storage overhead.
func (c *DatabaseCollection) CompactDocChannelHistory(ctx context.Context, docid string, seq uint64) ([]string, error) {
Expand Down Expand Up @@ -258,27 +314,27 @@ func (c *DatabaseCollection) CompactDocChannelHistory(ctx context.Context, docid
cas = doc.Cas
}

compactedChannels := make([]string, 0)
compactedChannels := make(base.Set)

doc.SyncData.ChannelSetHistory = slices.DeleteFunc(doc.SyncData.ChannelSetHistory, func(channel ChannelSetEntry) bool {
del := channel.End <= seq
if del {
compactedChannels = append(compactedChannels, channel.Name)
compactedChannels.Add(channel.Name)
}
return del
})

doc.SyncData.ChannelSet = slices.DeleteFunc(doc.SyncData.ChannelSet, func(channel ChannelSetEntry) bool {
del := channel.End != 0 && channel.End <= seq
if del {
compactedChannels = append(compactedChannels, channel.Name)
compactedChannels.Add(channel.Name)
}
return del
})

for chanName, chanEntry := range doc.SyncData.Channels {
if chanEntry != nil && chanEntry.Seq <= seq {
compactedChannels = append(compactedChannels, chanName)
compactedChannels.Add(chanName)
delete(doc.SyncData.Channels, chanName)
}
}
Expand Down Expand Up @@ -320,7 +376,9 @@ func (c *DatabaseCollection) CompactDocChannelHistory(ctx context.Context, docid
base.MouXattrName: rawMouXattr,
}
_, err = c.dataStore.UpdateXattrs(ctx, key, 0, cas, updatedXattr, opts)
return compactedChannels, err
compactedChannelArray := compactedChannels.ToArray()
slices.Sort(compactedChannelArray)
return compactedChannelArray, err
}

// unmarshalDocumentWithXattrs populates individual xattrs on unmarshalDocumentWithXattrs from a provided xattrs map
Expand Down
8 changes: 4 additions & 4 deletions docs/api/admin.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -125,10 +125,10 @@ paths:
$ref: './paths/admin/db-_index_init.yaml'
'/{keyspace}/_purge':
$ref: './paths/admin/keyspace-_purge.yaml'
'/{keyspace}/_history':
$ref: './paths/admin/keyspace-_history.yaml'
'/{keyspace}/_history/compact':
$ref: './paths/admin/keyspace-_history-compact.yaml'
'/{keyspace}/_channel_history/{docid}':
$ref: './paths/admin/keyspace-_channel_history.yaml'
'/{keyspace}/_channel_history/{docid}/compact':
$ref: './paths/admin/keyspace-_channel_history-compact.yaml'
'/{db}/_flush':
$ref: './paths/admin/db-_flush.yaml'
'/{db}/_online':
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,15 @@
# the file licenses/APL2.txt.
parameters:
- $ref: ../../components/parameters.yaml#/keyspace
- $ref: ../../components/parameters.yaml#/docid
post:
summary: Compact Channel History of Document
description: |-
Compacts inactive channel history entries from one or more documents before a specified sequence number.
Compacts channel history for a specified document. Channel history older than the specified sequence will be removed.

This endpoint removes all inactive channel entries (for sequences before the specified sequence number where the document left the channel),
This endpoint removes all channel entries (for sequences before the specified sequence number where the document left the channel),
effectively cleaning up historical channel membership information while preserving active channels and recent changes.
This is useful for reducing storage overhead when maintaining large document histories.
This can be useful for reducing metadata size for documents that frequently gain and lose access to channels.

Required Sync Gateway RBAC roles:

Expand All @@ -25,32 +26,22 @@ post:
schema:
type: object
required:
- doc_ids
- seq
properties:
doc_ids:
description: |-
List of document IDs whose inactive channels should be compacted.
type: array
items:
type: string
example:
- doc1
- doc2
seq:
description: |-
Channel history for inactive channels having end sequences earlier than this sequence will be removed from the specified document's metadata.
Channel history having end sequences earlier than this sequence will be removed from the specified document's metadata.
type: integer
format: int64
minimum: 0
minimum: 1
example: 12345
responses:
'200':
description: |-
Successfully compacted channel history from the specified documents.
Returns a mapping of document IDs to the list of channels that were compacted.
Successfully compacted channel history from the specified document.
Returns a list of channels that were compacted.

If a document ID has an empty array, it means no channels were pruned for that document.
If the response has an empty array, it means either no channels were compacted.

content:
application/json:
Expand All @@ -64,16 +55,13 @@ post:
description: |-
Array of channel names that were compacted.
description: |-
A mapping of document IDs (keys) to arrays of compacted channels (values).
A array of all the compacted channels
example:
doc1:
compacted_channels:
- channel1
- channel2
Comment thread
RIT3shSapata marked this conversation as resolved.
doc2:
- channel2
- channel3
'400':
description: 'Bad request. This could be due to invalid request parameters such as missing or malformed doc_ids array or invalid seq value.'
description: 'Bad request. This could be due to invalid request parameters such as invalid seq value.'
content:
application/json:
schema:
Expand Down
62 changes: 62 additions & 0 deletions docs/api/paths/admin/keyspace-_channel_history.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
# Copyright 2026-Present Couchbase, Inc.
#
# Use of this software is governed by the Business Source License included
# in the file licenses/BSL-Couchbase.txt. As of the Change Date specified
# in that file, in accordance with the Business Source License, use of this
# software will be governed by the Apache License, Version 2.0, included in
# the file licenses/APL2.txt.
parameters:
- $ref: ../../components/parameters.yaml#/keyspace
- $ref: ../../components/parameters.yaml#/docid
Comment thread
RIT3shSapata marked this conversation as resolved.
get:
summary: Get Channel History of Document
description: |-
Returns the channel revocation history for the specified document as a map of channel
names to the array of 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 may be included if they were previously revoked.

Multiple sequences for a given channel indicate that the document has lost access to that channel
more than once — each sequence represents a point in time at which the document was removed from
the channel.

Required Sync Gateway RBAC roles:

* Sync Gateway Application
* Sync Gateway Application Read Only
responses:
'200':
description: |-
Successfully retrieved the channel revocation history for the specified document.
Returns a JSON object mapping each channel name to an array of sequences at which
the document was removed from that channel.
content:
application/json:
schema:
type: object
additionalProperties:
type: array
items:
type: integer
format: int64
minimum: 1
description: Sequences at which the document was removed from this channel.
Comment on lines +37 to +43
description: Map of channel names to their revocation sequences.
Comment on lines +35 to +44
example:
channel1:
- 3
- 7
channel2:
- 5
'404':
description: Document not found.
content:
application/json:
schema:
$ref: ../../components/schemas.yaml#/HTTP-Error
'403':
$ref: ../../components/responses.yaml#/Unauthorized-database

tags:
- Document
operationId: get_keyspace-_channel_history
72 changes: 0 additions & 72 deletions docs/api/paths/admin/keyspace-_history.yaml

This file was deleted.

Loading
Loading