UBERF-8547 Do not update collaborative doc in platform when content not changed (#7115)

Signed-off-by: Alexander Onnikov <Alexander.Onnikov@xored.com>
This commit is contained in:
Alexander Onnikov 2024-11-07 13:18:53 +07:00 committed by GitHub
parent aa4eaeae84
commit afa485deb1
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 43 additions and 18 deletions

View File

@ -14,7 +14,7 @@
//
import { DocumentId } from '@hcengineering/collaborator-client'
import { MeasureContext } from '@hcengineering/core'
import { type Markup, MeasureContext } from '@hcengineering/core'
import {
Document,
Extension,
@ -37,19 +37,35 @@ export interface StorageConfiguration {
transformer: Transformer
}
type DocumentName = string
type ConnectionId = string
interface DocumentUpdates {
context: Context
collaborators: Set<ConnectionId>
}
export class StorageExtension implements Extension {
private readonly configuration: StorageConfiguration
private readonly collaborators = new Map<string, Set<string>>()
private readonly markups = new Map<string, Record<string, string>>()
private readonly updates = new Map<DocumentName, DocumentUpdates>()
private readonly markups = new Map<DocumentName, Record<Markup, Markup>>()
constructor (configuration: StorageConfiguration) {
this.configuration = configuration
}
async onChange ({ context, documentName }: withContext<onChangePayload>): Promise<any> {
const collaborators = this.collaborators.get(documentName) ?? new Set()
collaborators.add(context.connectionId)
this.collaborators.set(documentName, collaborators)
const { connectionId } = context
const updates = this.updates.get(documentName)
if (updates === undefined) {
const collaborators = new Set([connectionId])
this.updates.set(documentName, { context, collaborators })
} else {
updates.context = context
updates.collaborators.add(connectionId)
}
}
async onLoadDocument ({ context, documentName }: withContext<onLoadDocumentPayload>): Promise<any> {
@ -59,7 +75,7 @@ export class StorageExtension implements Extension {
return await this.loadDocument(documentName, context)
}
async afterLoadDocument ({ context, documentName, document }: withContext<afterLoadDocumentPayload>): Promise<any> {
async afterLoadDocument ({ documentName, document }: withContext<afterLoadDocumentPayload>): Promise<any> {
// remember the markup for the document
this.markups.set(documentName, this.configuration.transformer.fromYdoc(document))
}
@ -70,14 +86,14 @@ export class StorageExtension implements Extension {
ctx.info('store document', { documentName, connectionId })
const collaborators = this.collaborators.get(documentName)
if (collaborators === undefined || collaborators.size === 0) {
const updates = this.updates.get(documentName)
if (updates === undefined || updates.collaborators.size === 0) {
ctx.info('no changes for document', { documentName, connectionId })
return
}
this.collaborators.delete(documentName)
await this.storeDocument(documentName, document, context)
this.updates.delete(documentName)
await this.storeDocument(documentName, document, updates.context)
}
async onConnect ({ context, documentName, instance }: withContext<onConnectPayload>): Promise<any> {
@ -93,19 +109,19 @@ export class StorageExtension implements Extension {
const params = { documentName, connectionId, connections: document.getConnectionsCount() }
ctx.info('disconnect from document', params)
const collaborators = this.collaborators.get(documentName)
if (collaborators === undefined || !collaborators.has(connectionId)) {
const updates = this.updates.get(documentName)
if (updates === undefined || updates.collaborators.size === 0) {
ctx.info('no changes for document', { documentName, connectionId })
return
}
this.collaborators.delete(documentName)
this.updates.delete(documentName)
await this.storeDocument(documentName, document, context)
}
async afterUnloadDocument ({ documentName }: afterUnloadDocumentPayload): Promise<any> {
this.configuration.ctx.info('unload document', { documentName })
this.collaborators.delete(documentName)
this.updates.delete(documentName)
this.markups.delete(documentName)
}

View File

@ -53,7 +53,7 @@ export async function updateContent (
fragment.delete(0, fragment.length)
applyUpdate(document, update)
})
})
}, connection)
})
})
} finally {

View File

@ -34,6 +34,7 @@ import { Doc as YDoc } from 'yjs'
import { Context } from '../context'
import { CollabStorageAdapter } from './adapter'
import { areEqualMarkups } from '@hcengineering/text'
export class PlatformStorageAdapter implements CollabStorageAdapter {
constructor (private readonly storage: StorageAdapter) {}
@ -156,6 +157,14 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
): Promise<void> {
const { objectClass, objectId, objectAttr } = parsePlatformDocumentId(platformDocumentId)
const currMarkup = markup.curr[objectAttr]
const prevMarkup = markup.prev[objectAttr]
if (areEqualMarkups(currMarkup, prevMarkup)) {
ctx.info('markup not changed, skip platform update', { documentName })
return
}
const attribute = client.getHierarchy().findAttribute(objectClass, objectAttr)
if (attribute === undefined) {
ctx.warn('attribute not found', { documentName, objectClass, objectAttr })
@ -192,8 +201,8 @@ export class PlatformStorageAdapter implements CollabStorageAdapter {
attributeUpdates: {
attrKey: objectAttr,
attrClass: core.class.TypeMarkup,
prevValue: markup.prev[objectAttr],
set: [markup.curr[objectAttr]],
prevValue: prevMarkup,
set: [currMarkup],
added: [],
removed: [],
isMixin: hierarchy.isMixin(objectClass)