diff --git a/dist/cjs/replication-protocol/downstream.js b/dist/cjs/replication-protocol/downstream.js index 26fb440809e..5c7dd5cc11f 100644 --- a/dist/cjs/replication-protocol/downstream.js +++ b/dist/cjs/replication-protocol/downstream.js @@ -211,12 +211,15 @@ async function startReplicationDownstream(state) { if (!isAssumedMasterEqualToForkState && assumedMaster && assumedMaster.docData._rev && forkStateFullDoc && forkStateFullDoc._meta[state.input.identifier] && (0, _index.getHeightOfRevision)(forkStateFullDoc._rev) === forkStateFullDoc._meta[state.input.identifier]) { isAssumedMasterEqualToForkState = true; } - if (forkStateFullDoc && assumedMaster && isAssumedMasterEqualToForkState === false || forkStateFullDoc && !assumedMaster) { + if ((forkStateFullDoc && assumedMaster && isAssumedMasterEqualToForkState === false || forkStateFullDoc && !assumedMaster) && !(forkStateFullDoc._meta.o && forkStateFullDoc._meta.o.hash === identifierHash && forkStateFullDoc._meta.o._rev === (0, _index.getHeightOfRevision)(forkStateFullDoc._rev))) { /** * We have a non-upstream-replicated * local write to the fork. - * This means we ignore the downstream of this document - * because anyway the upstream will first resolve the conflict. + * This means either we have to upstream the local + * doc data first, or it means that the fork state was + * synced from the master but the process exited before + * the metadata was written. + * @link https://github.com/pubkey/rxdb/pull/7804 */ return _index.PROMISE_RESOLVE_VOID; } @@ -272,6 +275,17 @@ async function startReplicationDownstream(state) { if (state.input.keepMeta && masterState._meta) { newForkState._meta = masterState._meta; } + + /** + * Tag the write with its origin so a later downstream run can tell + * "fork differs from assumed master" caused by a local write apart + * from one caused by a lost meta write. A local write bumps the + * revision height and voids the marker. + */ + newForkState._meta.o = { + _rev: !forkStateFullDoc ? 1 : (0, _index.getHeightOfRevision)(forkStateFullDoc._rev) + 1, + hash: identifierHash + }; var forkWriteRow = { previous: forkStateFullDoc, document: newForkState diff --git a/dist/cjs/replication-protocol/downstream.js.map b/dist/cjs/replication-protocol/downstream.js.map index 1cbd98e6b8f..db8ae83ba5d 100644 --- a/dist/cjs/replication-protocol/downstream.js.map +++ b/dist/cjs/replication-protocol/downstream.js.map @@ -1 +1 @@ -{"version":3,"file":"downstream.js","names":["_rxjs","require","_rxError","_rxStorageHelper","_index","_checkpoint","_helper","_metaInstance","startReplicationDownstream","state","input","initialCheckpoint","downstream","checkpointDoc","getLastCheckpointDoc","setCheckpoint","identifierHash","hashFunction","identifier","replicationHandler","timer","openTasks","addNewTask","task","stats","down","taskWithTime","time","push","streamQueue","then","useTasks","length","events","active","next","innerTaskWithTime","ensureNotFalsy","shift","lastTimeMasterChangesRequested","downstreamResyncOnce","downstreamProcessChanges","firstSyncDone","getValue","canceled","sub","masterChangeStream$","pipe","mergeMap","ev","firstValueFrom","up","filter","s","subscribe","masterChangeStreamEmit","unsubscribe","checkpointQueue","lastCheckpoint","promises","downResult","masterChangesSince","pullBatchSize","documents","stackCheckpoints","checkpoint","persistFromMaster","Promise","all","tasks","docsOfAllTasks","forEach","Error","appendToArray","persistenceQueue","PROMISE_RESOLVE_VOID","nonPersistedFromMaster","docs","primaryPath","docData","docId","downDocsById","useCheckpoint","docIds","Object","keys","writeRowsToFork","writeRowsToForkById","writeRowsToMeta","useMetaWriteRows","forkInstance","findDocumentsById","getAssumedMasterState","currentForkStateList","assumedMasterState","currentForkState","Map","doc","set","map","forkStateFullDoc","get","forkStateDocData","writeDocToDocState","hasAttachments","undefined","masterState","assumedMaster","metaDocument","isResolvedConflict","_rev","isAssumedMasterEqualToForkState","conflictHandler","realMasterState","newDocumentState","r","isEqual","_meta","getHeightOfRevision","areStatesExactlyEqual","getMetaWriteRow","newForkState","assign","flatClone","_attachments","getDefaultRevision","lwt","now","nextRevisionHeight","keepMeta","forkWriteRow","previous","document","createRevision","bulkWrite","downstreamBulkWriteFlag","forkWriteResult","success","processed","error","status","newRxError","writeError","metaInstance","stripAttachmentsDataFromMetaWriteRows","metaWriteResult","id","documentId","catch","unhandledError"],"sources":["../../../src/replication-protocol/downstream.ts"],"sourcesContent":["import {\n firstValueFrom,\n filter,\n mergeMap\n} from 'rxjs';\nimport { newRxError } from '../rx-error.ts';\nimport { stackCheckpoints } from '../rx-storage-helper.ts';\nimport type {\n RxStorageInstanceReplicationState,\n BulkWriteRow,\n BulkWriteRowById,\n RxStorageReplicationMeta,\n RxDocumentData,\n ById,\n WithDeleted,\n DocumentsWithCheckpoint,\n WithDeletedAndAttachments\n} from '../types/index.d.ts';\nimport {\n appendToArray,\n createRevision,\n ensureNotFalsy,\n flatClone,\n getDefaultRevision,\n getHeightOfRevision,\n now,\n PROMISE_RESOLVE_VOID\n} from '../plugins/utils/index.ts';\nimport {\n getLastCheckpointDoc,\n setCheckpoint\n} from './checkpoint.ts';\nimport {\n stripAttachmentsDataFromMetaWriteRows,\n writeDocToDocState\n} from './helper.ts';\nimport {\n getAssumedMasterState,\n getMetaWriteRow\n} from './meta-instance.ts';\n\n/**\n * Writes all documents from the master to the fork.\n * The downstream has two operation modes\n * - Sync by iterating over the checkpoints via downstreamResyncOnce()\n * - Sync by listening to the changestream via downstreamProcessChanges()\n * We need this to be able to do initial syncs\n * and still can have fast event based sync when the client is not offline.\n */\nexport async function startReplicationDownstream(\n state: RxStorageInstanceReplicationState\n) {\n if (\n state.input.initialCheckpoint &&\n state.input.initialCheckpoint.downstream\n ) {\n const checkpointDoc = await getLastCheckpointDoc(state, 'down');\n if (!checkpointDoc) {\n await setCheckpoint(\n state,\n 'down',\n state.input.initialCheckpoint.downstream\n );\n }\n }\n\n const identifierHash = await state.input.hashFunction(state.input.identifier);\n const replicationHandler = state.input.replicationHandler;\n\n // used to detect which tasks etc can in it at which order.\n let timer = 0;\n\n\n type Task = DocumentsWithCheckpoint | 'RESYNC';\n type TaskWithTime = {\n time: number;\n task: Task;\n };\n const openTasks: TaskWithTime[] = [];\n\n\n function addNewTask(task: Task): void {\n state.stats.down.addNewTask = state.stats.down.addNewTask + 1;\n const taskWithTime = {\n time: timer++,\n task\n };\n openTasks.push(taskWithTime);\n state.streamQueue.down = state.streamQueue.down\n .then(() => {\n const useTasks: Task[] = [];\n while (openTasks.length > 0) {\n state.events.active.down.next(true);\n const innerTaskWithTime = ensureNotFalsy(openTasks.shift());\n\n /**\n * If the task came in before the last time we started the pull\n * from the master, then we can drop the task.\n */\n if (innerTaskWithTime.time < lastTimeMasterChangesRequested) {\n continue;\n }\n\n if (innerTaskWithTime.task === 'RESYNC') {\n if (useTasks.length === 0) {\n useTasks.push(innerTaskWithTime.task);\n break;\n } else {\n break;\n }\n }\n\n useTasks.push(innerTaskWithTime.task);\n }\n if (useTasks.length === 0) {\n return;\n }\n\n if (useTasks[0] === 'RESYNC') {\n return downstreamResyncOnce();\n } else {\n return downstreamProcessChanges(useTasks);\n }\n }).then(() => {\n state.events.active.down.next(false);\n if (\n !state.firstSyncDone.down.getValue() &&\n !state.events.canceled.getValue()\n ) {\n state.firstSyncDone.down.next(true);\n }\n });\n }\n addNewTask('RESYNC');\n\n /**\n * If a write on the master happens, we have to trigger the downstream.\n * Only do this if not canceled yet, otherwise firstValueFrom errors\n * when running on a completed observable.\n */\n if (!state.events.canceled.getValue()) {\n const sub = replicationHandler\n .masterChangeStream$\n .pipe(\n mergeMap(async (ev) => {\n /**\n * While a push is running, we have to delay all incoming\n * events from the server to not mix up the replication state.\n */\n await firstValueFrom(\n state.events.active.up.pipe(filter(s => !s))\n );\n return ev;\n })\n )\n .subscribe((task: Task) => {\n state.stats.down.masterChangeStreamEmit = state.stats.down.masterChangeStreamEmit + 1;\n addNewTask(task);\n });\n firstValueFrom(\n state.events.canceled.pipe(\n filter(canceled => !!canceled)\n )\n ).then(() => sub.unsubscribe());\n }\n\n\n /**\n * For faster performance, we directly start each write\n * and then await all writes at the end.\n */\n let lastTimeMasterChangesRequested: number = -1;\n async function downstreamResyncOnce() {\n state.stats.down.downstreamResyncOnce = state.stats.down.downstreamResyncOnce + 1;\n if (state.events.canceled.getValue()) {\n return;\n }\n\n state.checkpointQueue = state.checkpointQueue.then(() => getLastCheckpointDoc(state, 'down'));\n let lastCheckpoint: CheckpointType = await state.checkpointQueue;\n\n\n const promises: Promise[] = [];\n while (!state.events.canceled.getValue()) {\n lastTimeMasterChangesRequested = timer++;\n const downResult = await replicationHandler.masterChangesSince(\n lastCheckpoint,\n state.input.pullBatchSize\n );\n\n if (downResult.documents.length === 0) {\n break;\n }\n\n lastCheckpoint = stackCheckpoints([lastCheckpoint, downResult.checkpoint]);\n\n promises.push(\n persistFromMaster(\n downResult.documents,\n lastCheckpoint\n )\n );\n\n /**\n * By definition we stop pull when the pulled documents\n * do not fill up the pullBatchSize because we\n * can assume that the remote has no more documents.\n */\n if (downResult.documents.length < state.input.pullBatchSize) {\n break;\n }\n\n }\n await Promise.all(promises);\n }\n\n\n function downstreamProcessChanges(tasks: Task[]) {\n state.stats.down.downstreamProcessChanges = state.stats.down.downstreamProcessChanges + 1;\n const docsOfAllTasks: WithDeleted[] = [];\n let lastCheckpoint: CheckpointType | undefined = null as any;\n\n tasks.forEach(task => {\n if (task === 'RESYNC') {\n throw new Error('SNH');\n }\n appendToArray(docsOfAllTasks, task.documents);\n lastCheckpoint = stackCheckpoints([lastCheckpoint, task.checkpoint]);\n });\n return persistFromMaster(\n docsOfAllTasks,\n ensureNotFalsy(lastCheckpoint)\n );\n }\n\n\n /**\n * It can happen that the calls to masterChangesSince() or the changeStream()\n * are way faster then how fast the documents can be persisted.\n * Therefore we merge all incoming downResults into the nonPersistedFromMaster object\n * and process them together if possible.\n * This often bundles up single writes and improves performance\n * by processing the documents in bulks.\n */\n let persistenceQueue = PROMISE_RESOLVE_VOID;\n const nonPersistedFromMaster: {\n checkpoint?: CheckpointType;\n docs: ById>;\n } = {\n docs: {}\n };\n\n function persistFromMaster(\n docs: WithDeleted[],\n checkpoint: CheckpointType\n ): Promise {\n const primaryPath = state.primaryPath;\n state.stats.down.persistFromMaster = state.stats.down.persistFromMaster + 1;\n\n /**\n * Add the new docs to the non-persistent list\n */\n docs.forEach(docData => {\n const docId: string = (docData as any)[primaryPath];\n nonPersistedFromMaster.docs[docId] = docData;\n });\n nonPersistedFromMaster.checkpoint = checkpoint;\n\n /**\n * Run in the queue\n * with all open documents from nonPersistedFromMaster.\n */\n persistenceQueue = persistenceQueue.then(() => {\n\n const downDocsById: ById> = nonPersistedFromMaster.docs;\n nonPersistedFromMaster.docs = {};\n const useCheckpoint = nonPersistedFromMaster.checkpoint;\n const docIds = Object.keys(downDocsById);\n\n if (\n state.events.canceled.getValue() ||\n docIds.length === 0\n ) {\n return PROMISE_RESOLVE_VOID;\n }\n\n const writeRowsToFork: BulkWriteRow[] = [];\n const writeRowsToForkById: ById> = {};\n const writeRowsToMeta: BulkWriteRowById> = {};\n const useMetaWriteRows: BulkWriteRow>[] = [];\n\n return Promise.all([\n state.input.forkInstance.findDocumentsById(docIds, true),\n getAssumedMasterState(\n state,\n docIds\n )\n ]).then(([\n currentForkStateList,\n assumedMasterState\n ]) => {\n const currentForkState = new Map>();\n currentForkStateList.forEach(doc => currentForkState.set((doc as any)[primaryPath], doc));\n return Promise.all(\n docIds.map(async (docId) => {\n const forkStateFullDoc: RxDocumentData | undefined = currentForkState.get(docId);\n const forkStateDocData: WithDeletedAndAttachments | undefined = forkStateFullDoc\n ? writeDocToDocState(forkStateFullDoc, state.hasAttachments, false)\n : undefined\n ;\n const masterState = downDocsById[docId];\n const assumedMaster = assumedMasterState[docId];\n\n if (\n assumedMaster &&\n forkStateFullDoc &&\n assumedMaster.metaDocument.isResolvedConflict === forkStateFullDoc._rev\n ) {\n /**\n * The current fork state represents a resolved conflict\n * that first must be send to the master in the upstream.\n * All conflicts are resolved by the upstream.\n */\n // return PROMISE_RESOLVE_VOID;\n await state.streamQueue.up;\n }\n\n let isAssumedMasterEqualToForkState = !assumedMaster || !forkStateDocData ?\n false :\n await state.input.conflictHandler({\n realMasterState: assumedMaster.docData,\n newDocumentState: forkStateDocData\n }, 'downstream-check-if-equal-0').then(r => r.isEqual);\n if (\n !isAssumedMasterEqualToForkState &&\n (\n assumedMaster &&\n (assumedMaster.docData as any)._rev &&\n forkStateFullDoc &&\n forkStateFullDoc._meta[state.input.identifier] &&\n getHeightOfRevision(forkStateFullDoc._rev) === forkStateFullDoc._meta[state.input.identifier]\n )\n ) {\n isAssumedMasterEqualToForkState = true;\n }\n if (\n (\n forkStateFullDoc &&\n assumedMaster &&\n isAssumedMasterEqualToForkState === false\n ) ||\n (\n forkStateFullDoc && !assumedMaster\n )\n ) {\n /**\n * We have a non-upstream-replicated\n * local write to the fork.\n * This means we ignore the downstream of this document\n * because anyway the upstream will first resolve the conflict.\n */\n return PROMISE_RESOLVE_VOID;\n }\n\n const areStatesExactlyEqual = !forkStateDocData\n ? false\n : await state.input.conflictHandler(\n {\n realMasterState: masterState,\n newDocumentState: forkStateDocData\n },\n 'downstream-check-if-equal-1'\n ).then(r => r.isEqual);\n if (\n forkStateDocData &&\n areStatesExactlyEqual\n ) {\n /**\n * Document states are exactly equal.\n * This can happen when the replication is shut down\n * unexpected like when the user goes offline.\n *\n * Only when the assumedMaster is different from the forkState,\n * we have to patch the document in the meta instance.\n */\n if (\n !assumedMaster ||\n isAssumedMasterEqualToForkState === false\n ) {\n useMetaWriteRows.push(\n await getMetaWriteRow(\n state,\n forkStateDocData,\n assumedMaster ? assumedMaster.metaDocument : undefined\n )\n );\n }\n return PROMISE_RESOLVE_VOID;\n }\n\n /**\n * All other master states need to be written to the forkInstance\n * and metaInstance.\n */\n const newForkState = Object.assign(\n {},\n masterState,\n forkStateFullDoc ? {\n _meta: flatClone(forkStateFullDoc._meta),\n _attachments: state.hasAttachments && masterState._attachments ? masterState._attachments : {},\n _rev: getDefaultRevision()\n } : {\n _meta: {\n lwt: now()\n },\n _rev: getDefaultRevision(),\n _attachments: state.hasAttachments && masterState._attachments ? masterState._attachments : {}\n }\n );\n /**\n * If the remote works with revisions,\n * we store the height of the next fork-state revision\n * inside of the documents meta data.\n * By doing so we can filter it out in the upstream\n * and detect the document as being equal to master or not.\n * This is used for example in the CouchDB replication plugin.\n */\n if ((masterState as any)._rev) {\n const nextRevisionHeight = !forkStateFullDoc ? 1 : getHeightOfRevision(forkStateFullDoc._rev) + 1;\n newForkState._meta[state.input.identifier] = nextRevisionHeight;\n if (state.input.keepMeta) {\n newForkState._rev = (masterState as any)._rev;\n }\n }\n if (\n state.input.keepMeta &&\n (masterState as any)._meta\n ) {\n newForkState._meta = (masterState as any)._meta;\n }\n\n const forkWriteRow = {\n previous: forkStateFullDoc,\n document: newForkState\n };\n\n forkWriteRow.document._rev = forkWriteRow.document._rev ? forkWriteRow.document._rev : createRevision(\n identifierHash,\n forkWriteRow.previous\n );\n writeRowsToFork.push(forkWriteRow);\n writeRowsToForkById[docId] = forkWriteRow;\n writeRowsToMeta[docId] = await getMetaWriteRow(\n state,\n masterState,\n assumedMaster ? assumedMaster.metaDocument : undefined\n );\n })\n );\n }).then(async () => {\n if (writeRowsToFork.length > 0) {\n return state.input.forkInstance.bulkWrite(\n writeRowsToFork,\n await state.downstreamBulkWriteFlag\n ).then((forkWriteResult) => {\n forkWriteResult.success.forEach(doc => {\n const docId = (doc as any)[primaryPath];\n state.events.processed.down.next(writeRowsToForkById[docId]);\n useMetaWriteRows.push(writeRowsToMeta[docId]);\n });\n forkWriteResult.error.forEach(error => {\n /**\n * We do not have to care about downstream conflict errors here\n * because on conflict, it will be solved locally and result in another write.\n */\n if (error.status === 409) {\n return;\n }\n // other non-conflict errors must be handled\n state.events.error.next(newRxError('RC_PULL', {\n writeError: error\n }));\n });\n });\n }\n }).then(() => {\n if (useMetaWriteRows.length > 0) {\n return state.input.metaInstance.bulkWrite(\n stripAttachmentsDataFromMetaWriteRows(state, useMetaWriteRows),\n 'replication-down-write-meta'\n ).then(metaWriteResult => {\n metaWriteResult.error\n .forEach(writeError => {\n state.events.error.next(newRxError('RC_PULL', {\n id: writeError.documentId,\n writeError\n }));\n });\n });\n }\n }).then(() => {\n /**\n * For better performance we do not await checkpoint writes,\n * but to ensure order on parallel checkpoint writes,\n * we have to use a queue.\n */\n setCheckpoint(\n state,\n 'down',\n useCheckpoint\n );\n });\n }).catch(unhandledError => state.events.error.next(unhandledError));\n return persistenceQueue;\n }\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file +{"version":3,"file":"downstream.js","names":["_rxjs","require","_rxError","_rxStorageHelper","_index","_checkpoint","_helper","_metaInstance","startReplicationDownstream","state","input","initialCheckpoint","downstream","checkpointDoc","getLastCheckpointDoc","setCheckpoint","identifierHash","hashFunction","identifier","replicationHandler","timer","openTasks","addNewTask","task","stats","down","taskWithTime","time","push","streamQueue","then","useTasks","length","events","active","next","innerTaskWithTime","ensureNotFalsy","shift","lastTimeMasterChangesRequested","downstreamResyncOnce","downstreamProcessChanges","firstSyncDone","getValue","canceled","sub","masterChangeStream$","pipe","mergeMap","ev","firstValueFrom","up","filter","s","subscribe","masterChangeStreamEmit","unsubscribe","checkpointQueue","lastCheckpoint","promises","downResult","masterChangesSince","pullBatchSize","documents","stackCheckpoints","checkpoint","persistFromMaster","Promise","all","tasks","docsOfAllTasks","forEach","Error","appendToArray","persistenceQueue","PROMISE_RESOLVE_VOID","nonPersistedFromMaster","docs","primaryPath","docData","docId","downDocsById","useCheckpoint","docIds","Object","keys","writeRowsToFork","writeRowsToForkById","writeRowsToMeta","useMetaWriteRows","forkInstance","findDocumentsById","getAssumedMasterState","currentForkStateList","assumedMasterState","currentForkState","Map","doc","set","map","forkStateFullDoc","get","forkStateDocData","writeDocToDocState","hasAttachments","undefined","masterState","assumedMaster","metaDocument","isResolvedConflict","_rev","isAssumedMasterEqualToForkState","conflictHandler","realMasterState","newDocumentState","r","isEqual","_meta","getHeightOfRevision","o","hash","areStatesExactlyEqual","getMetaWriteRow","newForkState","assign","flatClone","_attachments","getDefaultRevision","lwt","now","nextRevisionHeight","keepMeta","forkWriteRow","previous","document","createRevision","bulkWrite","downstreamBulkWriteFlag","forkWriteResult","success","processed","error","status","newRxError","writeError","metaInstance","stripAttachmentsDataFromMetaWriteRows","metaWriteResult","id","documentId","catch","unhandledError"],"sources":["../../../src/replication-protocol/downstream.ts"],"sourcesContent":["import {\n firstValueFrom,\n filter,\n mergeMap\n} from 'rxjs';\nimport { newRxError } from '../rx-error.ts';\nimport { stackCheckpoints } from '../rx-storage-helper.ts';\nimport type {\n RxStorageInstanceReplicationState,\n BulkWriteRow,\n BulkWriteRowById,\n RxStorageReplicationMeta,\n RxDocumentData,\n ById,\n WithDeleted,\n DocumentsWithCheckpoint,\n WithDeletedAndAttachments\n} from '../types/index.d.ts';\nimport {\n appendToArray,\n createRevision,\n ensureNotFalsy,\n flatClone,\n getDefaultRevision,\n getHeightOfRevision,\n now,\n PROMISE_RESOLVE_VOID\n} from '../plugins/utils/index.ts';\nimport {\n getLastCheckpointDoc,\n setCheckpoint\n} from './checkpoint.ts';\nimport {\n stripAttachmentsDataFromMetaWriteRows,\n writeDocToDocState\n} from './helper.ts';\nimport {\n getAssumedMasterState,\n getMetaWriteRow\n} from './meta-instance.ts';\n\n/**\n * Writes all documents from the master to the fork.\n * The downstream has two operation modes\n * - Sync by iterating over the checkpoints via downstreamResyncOnce()\n * - Sync by listening to the changestream via downstreamProcessChanges()\n * We need this to be able to do initial syncs\n * and still can have fast event based sync when the client is not offline.\n */\nexport async function startReplicationDownstream(\n state: RxStorageInstanceReplicationState\n) {\n if (\n state.input.initialCheckpoint &&\n state.input.initialCheckpoint.downstream\n ) {\n const checkpointDoc = await getLastCheckpointDoc(state, 'down');\n if (!checkpointDoc) {\n await setCheckpoint(\n state,\n 'down',\n state.input.initialCheckpoint.downstream\n );\n }\n }\n\n const identifierHash = await state.input.hashFunction(state.input.identifier);\n const replicationHandler = state.input.replicationHandler;\n\n // used to detect which tasks etc can in it at which order.\n let timer = 0;\n\n\n type Task = DocumentsWithCheckpoint | 'RESYNC';\n type TaskWithTime = {\n time: number;\n task: Task;\n };\n const openTasks: TaskWithTime[] = [];\n\n\n function addNewTask(task: Task): void {\n state.stats.down.addNewTask = state.stats.down.addNewTask + 1;\n const taskWithTime = {\n time: timer++,\n task\n };\n openTasks.push(taskWithTime);\n state.streamQueue.down = state.streamQueue.down\n .then(() => {\n const useTasks: Task[] = [];\n while (openTasks.length > 0) {\n state.events.active.down.next(true);\n const innerTaskWithTime = ensureNotFalsy(openTasks.shift());\n\n /**\n * If the task came in before the last time we started the pull\n * from the master, then we can drop the task.\n */\n if (innerTaskWithTime.time < lastTimeMasterChangesRequested) {\n continue;\n }\n\n if (innerTaskWithTime.task === 'RESYNC') {\n if (useTasks.length === 0) {\n useTasks.push(innerTaskWithTime.task);\n break;\n } else {\n break;\n }\n }\n\n useTasks.push(innerTaskWithTime.task);\n }\n if (useTasks.length === 0) {\n return;\n }\n\n if (useTasks[0] === 'RESYNC') {\n return downstreamResyncOnce();\n } else {\n return downstreamProcessChanges(useTasks);\n }\n }).then(() => {\n state.events.active.down.next(false);\n if (\n !state.firstSyncDone.down.getValue() &&\n !state.events.canceled.getValue()\n ) {\n state.firstSyncDone.down.next(true);\n }\n });\n }\n addNewTask('RESYNC');\n\n /**\n * If a write on the master happens, we have to trigger the downstream.\n * Only do this if not canceled yet, otherwise firstValueFrom errors\n * when running on a completed observable.\n */\n if (!state.events.canceled.getValue()) {\n const sub = replicationHandler\n .masterChangeStream$\n .pipe(\n mergeMap(async (ev) => {\n /**\n * While a push is running, we have to delay all incoming\n * events from the server to not mix up the replication state.\n */\n await firstValueFrom(\n state.events.active.up.pipe(filter(s => !s))\n );\n return ev;\n })\n )\n .subscribe((task: Task) => {\n state.stats.down.masterChangeStreamEmit = state.stats.down.masterChangeStreamEmit + 1;\n addNewTask(task);\n });\n firstValueFrom(\n state.events.canceled.pipe(\n filter(canceled => !!canceled)\n )\n ).then(() => sub.unsubscribe());\n }\n\n\n /**\n * For faster performance, we directly start each write\n * and then await all writes at the end.\n */\n let lastTimeMasterChangesRequested: number = -1;\n async function downstreamResyncOnce() {\n state.stats.down.downstreamResyncOnce = state.stats.down.downstreamResyncOnce + 1;\n if (state.events.canceled.getValue()) {\n return;\n }\n\n state.checkpointQueue = state.checkpointQueue.then(() => getLastCheckpointDoc(state, 'down'));\n let lastCheckpoint: CheckpointType = await state.checkpointQueue;\n\n\n const promises: Promise[] = [];\n while (!state.events.canceled.getValue()) {\n lastTimeMasterChangesRequested = timer++;\n const downResult = await replicationHandler.masterChangesSince(\n lastCheckpoint,\n state.input.pullBatchSize\n );\n\n if (downResult.documents.length === 0) {\n break;\n }\n\n lastCheckpoint = stackCheckpoints([lastCheckpoint, downResult.checkpoint]);\n\n promises.push(\n persistFromMaster(\n downResult.documents,\n lastCheckpoint\n )\n );\n\n /**\n * By definition we stop pull when the pulled documents\n * do not fill up the pullBatchSize because we\n * can assume that the remote has no more documents.\n */\n if (downResult.documents.length < state.input.pullBatchSize) {\n break;\n }\n\n }\n await Promise.all(promises);\n }\n\n\n function downstreamProcessChanges(tasks: Task[]) {\n state.stats.down.downstreamProcessChanges = state.stats.down.downstreamProcessChanges + 1;\n const docsOfAllTasks: WithDeleted[] = [];\n let lastCheckpoint: CheckpointType | undefined = null as any;\n\n tasks.forEach(task => {\n if (task === 'RESYNC') {\n throw new Error('SNH');\n }\n appendToArray(docsOfAllTasks, task.documents);\n lastCheckpoint = stackCheckpoints([lastCheckpoint, task.checkpoint]);\n });\n return persistFromMaster(\n docsOfAllTasks,\n ensureNotFalsy(lastCheckpoint)\n );\n }\n\n\n /**\n * It can happen that the calls to masterChangesSince() or the changeStream()\n * are way faster then how fast the documents can be persisted.\n * Therefore we merge all incoming downResults into the nonPersistedFromMaster object\n * and process them together if possible.\n * This often bundles up single writes and improves performance\n * by processing the documents in bulks.\n */\n let persistenceQueue = PROMISE_RESOLVE_VOID;\n const nonPersistedFromMaster: {\n checkpoint?: CheckpointType;\n docs: ById>;\n } = {\n docs: {}\n };\n\n function persistFromMaster(\n docs: WithDeleted[],\n checkpoint: CheckpointType\n ): Promise {\n const primaryPath = state.primaryPath;\n state.stats.down.persistFromMaster = state.stats.down.persistFromMaster + 1;\n\n /**\n * Add the new docs to the non-persistent list\n */\n docs.forEach(docData => {\n const docId: string = (docData as any)[primaryPath];\n nonPersistedFromMaster.docs[docId] = docData;\n });\n nonPersistedFromMaster.checkpoint = checkpoint;\n\n /**\n * Run in the queue\n * with all open documents from nonPersistedFromMaster.\n */\n persistenceQueue = persistenceQueue.then(() => {\n\n const downDocsById: ById> = nonPersistedFromMaster.docs;\n nonPersistedFromMaster.docs = {};\n const useCheckpoint = nonPersistedFromMaster.checkpoint;\n const docIds = Object.keys(downDocsById);\n\n if (\n state.events.canceled.getValue() ||\n docIds.length === 0\n ) {\n return PROMISE_RESOLVE_VOID;\n }\n\n const writeRowsToFork: BulkWriteRow[] = [];\n const writeRowsToForkById: ById> = {};\n const writeRowsToMeta: BulkWriteRowById> = {};\n const useMetaWriteRows: BulkWriteRow>[] = [];\n\n return Promise.all([\n state.input.forkInstance.findDocumentsById(docIds, true),\n getAssumedMasterState(\n state,\n docIds\n )\n ]).then(([\n currentForkStateList,\n assumedMasterState\n ]) => {\n const currentForkState = new Map>();\n currentForkStateList.forEach(doc => currentForkState.set((doc as any)[primaryPath], doc));\n return Promise.all(\n docIds.map(async (docId) => {\n const forkStateFullDoc: RxDocumentData | undefined = currentForkState.get(docId);\n const forkStateDocData: WithDeletedAndAttachments | undefined = forkStateFullDoc\n ? writeDocToDocState(forkStateFullDoc, state.hasAttachments, false)\n : undefined\n ;\n const masterState = downDocsById[docId];\n const assumedMaster = assumedMasterState[docId];\n\n if (\n assumedMaster &&\n forkStateFullDoc &&\n assumedMaster.metaDocument.isResolvedConflict === forkStateFullDoc._rev\n ) {\n /**\n * The current fork state represents a resolved conflict\n * that first must be send to the master in the upstream.\n * All conflicts are resolved by the upstream.\n */\n // return PROMISE_RESOLVE_VOID;\n await state.streamQueue.up;\n }\n\n let isAssumedMasterEqualToForkState = !assumedMaster || !forkStateDocData ?\n false :\n await state.input.conflictHandler({\n realMasterState: assumedMaster.docData,\n newDocumentState: forkStateDocData\n }, 'downstream-check-if-equal-0').then(r => r.isEqual);\n if (\n !isAssumedMasterEqualToForkState &&\n (\n assumedMaster &&\n (assumedMaster.docData as any)._rev &&\n forkStateFullDoc &&\n forkStateFullDoc._meta[state.input.identifier] &&\n getHeightOfRevision(forkStateFullDoc._rev) === forkStateFullDoc._meta[state.input.identifier]\n )\n ) {\n isAssumedMasterEqualToForkState = true;\n }\n if (\n (\n (\n forkStateFullDoc &&\n assumedMaster &&\n isAssumedMasterEqualToForkState === false\n ) ||\n (\n forkStateFullDoc && !assumedMaster\n )\n ) &&\n !(\n forkStateFullDoc._meta.o &&\n (\n forkStateFullDoc._meta.o.hash === identifierHash &&\n forkStateFullDoc._meta.o._rev === getHeightOfRevision(forkStateFullDoc._rev)\n )\n )\n ) {\n /**\n * We have a non-upstream-replicated\n * local write to the fork.\n * This means either we have to upstream the local\n * doc data first, or it means that the fork state was\n * synced from the master but the process exited before\n * the metadata was written.\n * @link https://github.com/pubkey/rxdb/pull/7804\n */\n return PROMISE_RESOLVE_VOID;\n }\n\n const areStatesExactlyEqual = !forkStateDocData\n ? false\n : await state.input.conflictHandler(\n {\n realMasterState: masterState,\n newDocumentState: forkStateDocData\n },\n 'downstream-check-if-equal-1'\n ).then(r => r.isEqual);\n if (\n forkStateDocData &&\n areStatesExactlyEqual\n ) {\n /**\n * Document states are exactly equal.\n * This can happen when the replication is shut down\n * unexpected like when the user goes offline.\n *\n * Only when the assumedMaster is different from the forkState,\n * we have to patch the document in the meta instance.\n */\n if (\n !assumedMaster ||\n isAssumedMasterEqualToForkState === false\n ) {\n useMetaWriteRows.push(\n await getMetaWriteRow(\n state,\n forkStateDocData,\n assumedMaster ? assumedMaster.metaDocument : undefined\n )\n );\n }\n return PROMISE_RESOLVE_VOID;\n }\n\n /**\n * All other master states need to be written to the forkInstance\n * and metaInstance.\n */\n const newForkState = Object.assign(\n {},\n masterState,\n forkStateFullDoc ? {\n _meta: flatClone(forkStateFullDoc._meta),\n _attachments: state.hasAttachments && masterState._attachments ? masterState._attachments : {},\n _rev: getDefaultRevision()\n } : {\n _meta: {\n lwt: now()\n },\n _rev: getDefaultRevision(),\n _attachments: state.hasAttachments && masterState._attachments ? masterState._attachments : {}\n }\n );\n /**\n * If the remote works with revisions,\n * we store the height of the next fork-state revision\n * inside of the documents meta data.\n * By doing so we can filter it out in the upstream\n * and detect the document as being equal to master or not.\n * This is used for example in the CouchDB replication plugin.\n */\n if ((masterState as any)._rev) {\n const nextRevisionHeight = !forkStateFullDoc ? 1 : getHeightOfRevision(forkStateFullDoc._rev) + 1;\n newForkState._meta[state.input.identifier] = nextRevisionHeight;\n if (state.input.keepMeta) {\n newForkState._rev = (masterState as any)._rev;\n }\n }\n if (\n state.input.keepMeta &&\n (masterState as any)._meta\n ) {\n newForkState._meta = (masterState as any)._meta;\n }\n\n /**\n * Tag the write with its origin so a later downstream run can tell\n * \"fork differs from assumed master\" caused by a local write apart\n * from one caused by a lost meta write. A local write bumps the\n * revision height and voids the marker.\n */\n newForkState._meta.o = {\n _rev: !forkStateFullDoc ? 1 : getHeightOfRevision(forkStateFullDoc._rev) + 1,\n hash: identifierHash\n };\n\n const forkWriteRow = {\n previous: forkStateFullDoc,\n document: newForkState\n };\n\n forkWriteRow.document._rev = forkWriteRow.document._rev ? forkWriteRow.document._rev : createRevision(\n identifierHash,\n forkWriteRow.previous\n );\n writeRowsToFork.push(forkWriteRow);\n writeRowsToForkById[docId] = forkWriteRow;\n writeRowsToMeta[docId] = await getMetaWriteRow(\n state,\n masterState,\n assumedMaster ? assumedMaster.metaDocument : undefined\n );\n })\n );\n }).then(async () => {\n if (writeRowsToFork.length > 0) {\n return state.input.forkInstance.bulkWrite(\n writeRowsToFork,\n await state.downstreamBulkWriteFlag\n ).then((forkWriteResult) => {\n forkWriteResult.success.forEach(doc => {\n const docId = (doc as any)[primaryPath];\n state.events.processed.down.next(writeRowsToForkById[docId]);\n useMetaWriteRows.push(writeRowsToMeta[docId]);\n });\n forkWriteResult.error.forEach(error => {\n /**\n * We do not have to care about downstream conflict errors here\n * because on conflict, it will be solved locally and result in another write.\n */\n if (error.status === 409) {\n return;\n }\n // other non-conflict errors must be handled\n state.events.error.next(newRxError('RC_PULL', {\n writeError: error\n }));\n });\n });\n }\n }).then(() => {\n if (useMetaWriteRows.length > 0) {\n return state.input.metaInstance.bulkWrite(\n stripAttachmentsDataFromMetaWriteRows(state, useMetaWriteRows),\n 'replication-down-write-meta'\n ).then(metaWriteResult => {\n metaWriteResult.error\n .forEach(writeError => {\n state.events.error.next(newRxError('RC_PULL', {\n id: writeError.documentId,\n writeError\n }));\n });\n });\n }\n }).then(() => {\n /**\n * For better performance we do not await checkpoint writes,\n * but to ensure order on parallel checkpoint writes,\n * we have to use a queue.\n */\n setCheckpoint(\n state,\n 'down',\n useCheckpoint\n );\n });\n }).catch(unhandledError => state.events.error.next(unhandledError));\n return persistenceQueue;\n }\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/cjs/types/rx-document.d.js.map b/dist/cjs/types/rx-document.d.js.map index eb6baf2addd..c5a9e8f8a60 100644 --- a/dist/cjs/types/rx-document.d.js.map +++ b/dist/cjs/types/rx-document.d.js.map @@ -1 +1 @@ -{"version":3,"file":"rx-document.d.js","names":[],"sources":["../../../src/types/rx-document.d.ts"],"sourcesContent":["import {\n Observable\n} from 'rxjs';\n\nimport type {\n RxCollection,\n} from './rx-collection.d.ts';\nimport type {\n RxAttachment,\n RxAttachmentCreator\n} from './rx-attachment.d.ts';\nimport type { RxDocumentData, WithDeleted } from './rx-storage.d.ts';\nimport type { RxChangeEvent } from './rx-change-event.d.ts';\nimport type { DeepReadonly, MaybePromise, PlainJsonValue } from './util.d.ts';\nimport type { UpdateQuery } from './plugins/update.d.ts';\nimport type { CRDTEntry } from './plugins/crdt.d.ts';\n\n\n\nexport type RxDocument = RxDocumentBase<\n RxDocumentType,\n OrmMethods,\n Reactivity\n> & RxDocumentType & OrmMethods & ExtendObservables & ExtendReactivity;\n\n\n/**\n * Extend the base properties by the property$ fields\n * so it knows that RxDocument.age also has RxDocument.age$ which is\n * an observable.\n * TODO how to do this for the nested fields?\n */\ntype ExtendObservables = {\n [P in keyof RxDocumentType as `${string & P}$`]: Observable;\n};\n\ntype ExtendReactivity = {\n [P in keyof RxDocumentType as `${string & P}$$`]: Reactivity;\n};\n\n/**\n * The public facing modify update function.\n * It only gets the document parts as input, that\n * are mutateable by the user.\n */\nexport type ModifyFunction = (\n doc: WithDeleted\n) => MaybePromise> | MaybePromise;\n\n/**\n * Meta data that is attached to each document by RxDB.\n */\nexport type RxDocumentMeta = {\n /**\n * Last write time.\n * Unix epoch in milliseconds.\n */\n lwt: number;\n\n /**\n * Any other value can be attached to the _meta data.\n * Mostly done by plugins to mark documents.\n */\n [k: string]: PlainJsonValue;\n};\n\nexport declare interface RxDocumentBase {\n isInstanceOfRxDocument: true;\n collection: RxCollection;\n readonly deleted: boolean;\n\n readonly $: Observable>;\n readonly $$: Reactivity;\n readonly deleted$: Observable;\n readonly deleted$$: Reactivity;\n\n readonly primary: string;\n readonly allAttachments$: Observable[]>;\n\n // internal things\n _data: RxDocumentData;\n primaryPath: string;\n revision: string;\n /**\n * Used to de-duplicate the enriched property objects\n * of the document.\n */\n _propertyCache: Map;\n $emit(cE: RxChangeEvent): void;\n _saveData(newData: any, oldData: any): Promise>;\n // /internal things\n\n // Returns the latest state of the document\n getLatest(): RxDocument;\n\n\n get$(path: string): Observable;\n get$$(path: string): Reactivity;\n get(objPath: string): DeepReadonly;\n populate(objPath: string): Promise | any | null>;\n\n /**\n * mutate the document with a function\n */\n modify(mutationFunction: ModifyFunction, context?: string): Promise>;\n incrementalModify(mutationFunction: ModifyFunction, context?: string): Promise>;\n\n /**\n * patches the given properties\n */\n patch(patch: Partial): Promise>;\n incrementalPatch(patch: Partial): Promise>;\n\n update(updateObj: UpdateQuery): Promise>;\n incrementalUpdate(updateObj: UpdateQuery): Promise>;\n\n updateCRDT(updateObj: CRDTEntry | CRDTEntry[]): Promise>;\n\n remove(): Promise>;\n incrementalRemove(): Promise>;\n\n // only for temporary documents\n set(objPath: string, value: any): RxDocument;\n save(): Promise;\n\n // attachments\n putAttachment(\n creator: RxAttachmentCreator\n ): Promise>;\n getAttachment(id: string): RxAttachment | null;\n allAttachments(): RxAttachment[];\n\n toJSON(withRevAndAttachments: true): DeepReadonly>;\n toJSON(withRevAndAttachments?: false): DeepReadonly;\n\n toMutableJSON(withRevAndAttachments: true): RxDocumentData;\n toMutableJSON(withRevAndAttachments?: false): RxDocType;\n\n destroy(): void;\n}\n"],"mappings":"","ignoreList":[]} \ No newline at end of file +{"version":3,"file":"rx-document.d.js","names":[],"sources":["../../../src/types/rx-document.d.ts"],"sourcesContent":["import {\n Observable\n} from 'rxjs';\n\nimport type {\n RxCollection,\n} from './rx-collection.d.ts';\nimport type {\n RxAttachment,\n RxAttachmentCreator\n} from './rx-attachment.d.ts';\nimport type { RxDocumentData, WithDeleted } from './rx-storage.d.ts';\nimport type { RxChangeEvent } from './rx-change-event.d.ts';\nimport type { DeepReadonly, MaybePromise, PlainJsonValue } from './util.d.ts';\nimport type { UpdateQuery } from './plugins/update.d.ts';\nimport type { CRDTEntry } from './plugins/crdt.d.ts';\n\n\n\nexport type RxDocument = RxDocumentBase<\n RxDocumentType,\n OrmMethods,\n Reactivity\n> & RxDocumentType & OrmMethods & ExtendObservables & ExtendReactivity;\n\n\n/**\n * Extend the base properties by the property$ fields\n * so it knows that RxDocument.age also has RxDocument.age$ which is\n * an observable.\n * TODO how to do this for the nested fields?\n */\ntype ExtendObservables = {\n [P in keyof RxDocumentType as `${string & P}$`]: Observable;\n};\n\ntype ExtendReactivity = {\n [P in keyof RxDocumentType as `${string & P}$$`]: Reactivity;\n};\n\n/**\n * The public facing modify update function.\n * It only gets the document parts as input, that\n * are mutateable by the user.\n */\nexport type ModifyFunction = (\n doc: WithDeleted\n) => MaybePromise> | MaybePromise;\n\n/**\n * Meta data that is attached to each document by RxDB.\n */\nexport type RxDocumentMeta = {\n /**\n * Last write time.\n * Unix epoch in milliseconds.\n */\n lwt: number;\n\n /**\n * The replication plugins \"tags\" the origin\n * of writes to later know if a write came from\n * the replication or was done locally.\n */\n o?: {\n hash: string;\n _rev: number;\n };\n\n /**\n * Any other value can be attached to the _meta data.\n * Mostly done by plugins to mark documents.\n */\n [k: string]: PlainJsonValue | undefined;\n};\n\nexport declare interface RxDocumentBase {\n isInstanceOfRxDocument: true;\n collection: RxCollection;\n readonly deleted: boolean;\n\n readonly $: Observable>;\n readonly $$: Reactivity;\n readonly deleted$: Observable;\n readonly deleted$$: Reactivity;\n\n readonly primary: string;\n readonly allAttachments$: Observable[]>;\n\n // internal things\n _data: RxDocumentData;\n primaryPath: string;\n revision: string;\n /**\n * Used to de-duplicate the enriched property objects\n * of the document.\n */\n _propertyCache: Map;\n $emit(cE: RxChangeEvent): void;\n _saveData(newData: any, oldData: any): Promise>;\n // /internal things\n\n // Returns the latest state of the document\n getLatest(): RxDocument;\n\n\n get$(path: string): Observable;\n get$$(path: string): Reactivity;\n get(objPath: string): DeepReadonly;\n populate(objPath: string): Promise | any | null>;\n\n /**\n * mutate the document with a function\n */\n modify(mutationFunction: ModifyFunction, context?: string): Promise>;\n incrementalModify(mutationFunction: ModifyFunction, context?: string): Promise>;\n\n /**\n * patches the given properties\n */\n patch(patch: Partial): Promise>;\n incrementalPatch(patch: Partial): Promise>;\n\n update(updateObj: UpdateQuery): Promise>;\n incrementalUpdate(updateObj: UpdateQuery): Promise>;\n\n updateCRDT(updateObj: CRDTEntry | CRDTEntry[]): Promise>;\n\n remove(): Promise>;\n incrementalRemove(): Promise>;\n\n // only for temporary documents\n set(objPath: string, value: any): RxDocument;\n save(): Promise;\n\n // attachments\n putAttachment(\n creator: RxAttachmentCreator\n ): Promise>;\n getAttachment(id: string): RxAttachment | null;\n allAttachments(): RxAttachment[];\n\n toJSON(withRevAndAttachments: true): DeepReadonly>;\n toJSON(withRevAndAttachments?: false): DeepReadonly;\n\n toMutableJSON(withRevAndAttachments: true): RxDocumentData;\n toMutableJSON(withRevAndAttachments?: false): RxDocType;\n\n destroy(): void;\n}\n"],"mappings":"","ignoreList":[]} \ No newline at end of file diff --git a/dist/cjs/types/util.d.js.map b/dist/cjs/types/util.d.js.map index 9d1b26e0974..08295e33e92 100644 --- a/dist/cjs/types/util.d.js.map +++ b/dist/cjs/types/util.d.js.map @@ -1 +1 @@ -{"version":3,"file":"util.d.js","names":[],"sources":["../../../src/types/util.d.ts"],"sourcesContent":["import type { RxStorage } from './rx-storage.interface';\n\nexport type MaybePromise = Promise | T;\n\n\nexport type PlainJsonValue = string | number | boolean | PlainSimpleJsonObject | PlainSimpleJsonObject[] | PlainJsonValue[];\nexport type PlainSimpleJsonObject = {\n [k: string]: PlainJsonValue | PlainJsonValue[];\n};\n\n/**\n * @link https://stackoverflow.com/a/49670389/3443137\n */\ntype DeepReadonly =\n T extends (infer R)[] ? DeepReadonlyArray :\n T extends Function ? T :\n T extends object ? DeepReadonlyObject :\n T;\n\ninterface DeepReadonlyArray extends ReadonlyArray> { }\n\ntype DeepReadonlyObject = {\n readonly [P in keyof T]: DeepReadonly;\n};\n\nexport type MaybeReadonly = T | Readonly;\n\n\n/**\n * Opposite of DeepReadonly,\n * makes everything mutable again.\n */\ntype DeepMutable = (\n T extends object\n ? {\n -readonly [K in keyof T]: (\n T[K] extends object\n ? DeepMutable\n : T[K]\n )\n }\n : never\n);\n\n/**\n * Can be used like 'keyof'\n * but only represents the string keys, not the Symbols or numbers.\n * @link https://stackoverflow.com/a/51808262/3443137\n */\nexport type StringKeys = Extract;\n\nexport type AnyKeys = { [P in keyof T]?: T[P] | any };\nexport interface AnyObject {\n [k: string]: any;\n}\n\n/**\n * @link https://dev.to/vborodulin/ts-how-to-override-properties-with-type-intersection-554l\n */\nexport type Override = Omit & T2;\n\n\n\nexport type ById = {\n [id: string]: T;\n};\n\n/**\n * Must be async to support async hashing like from the WebCrypto API.\n */\nexport type HashFunction = (input: string) => Promise;\n\nexport declare type QueryMatcher = (doc: DocType | DeepReadonly) => boolean;\n\n/**\n * To have a deterministic sorting, we cannot return 0,\n * we only return 1 or -1.\n * This ensures that we always end with the same output array, no mather of the\n * pre-sorting of the input array.\n */\nexport declare type DeterministicSortComparator = (a: DocType, b: DocType) => 1 | -1;\n\n/**\n * To test a storage, we need these\n * configuration values.\n */\nexport type RxTestStorage = {\n // can be used to setup async stuff\n readonly init?: () => any;\n // TODO remove name here, it can be read out already via getStorage().name\n readonly name: string;\n readonly getStorage: () => RxStorage;\n /**\n * Returns a storage that is used in performance tests.\n * For example in a browser it should return the storage with an IndexedDB based adapter,\n * while in node.js it must use the filesystem.\n */\n readonly getPerformanceStorage: () => {\n storage: RxStorage;\n /**\n * A description that describes the storage and setting.\n * For example 'dexie-native'.\n */\n description: string;\n };\n /**\n * True if the storage is able to\n * keep data after an instance is closed and opened again.\n */\n readonly hasPersistence: boolean;\n readonly hasMultiInstance: boolean;\n readonly hasAttachments: boolean;\n\n /**\n * Some storages likes the memory-synced storage,\n * are not able to provide a replication while guaranteeing\n * data integrity.\n */\n readonly hasReplication: boolean;\n\n /**\n * To make it possible to test alternative encryption plugins,\n * you can specify hasEncryption to signal\n * the test runner that the given storage already contains an\n * encryption plugin that should be used to test encryption tests.\n * Otherwise the encryption-crypto-js plugin will be tested.\n *\n * hasEncryption must contain a function that is able\n * to create a new password.\n */\n readonly hasEncryption?: () => Promise;\n};\n\n\n/**\n * The paths as strings-type of nested object\n * @link https://stackoverflow.com/a/58436959/3443137\n */\ntype Join = K extends string | number ?\n P extends string | number ?\n `${K}${'' extends P ? '' : '.'}${P}`\n : never : never;\n\nexport type Paths = [D] extends [never] ? never : T extends object ?\n { [K in keyof T]-?: K extends string | number ?\n `${K}` | (Paths extends infer R ? Join : never)\n : never\n }[keyof T] : '';\n\nexport type Leaves = [D] extends [never] ? never : T extends object ?\n { [K in keyof T]-?: Join> }[keyof T] : '';\ntype Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\n 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...0[]];\n"],"mappings":"","ignoreList":[]} \ No newline at end of file +{"version":3,"file":"util.d.js","names":[],"sources":["../../../src/types/util.d.ts"],"sourcesContent":["import type { RxStorage } from './rx-storage.interface';\n\nexport type MaybePromise = Promise | T;\n\n\nexport type PlainJsonValue =\n string |\n number |\n boolean |\n PlainSimpleJsonObject |\n PlainSimpleJsonObject[] |\n PlainJsonValue[] |\n { [key: string]: PlainJsonValue; };\nexport type PlainSimpleJsonObject = {\n [k: string]: PlainJsonValue | PlainJsonValue[];\n};\n\n/**\n * @link https://stackoverflow.com/a/49670389/3443137\n */\ntype DeepReadonly =\n T extends (infer R)[] ? DeepReadonlyArray :\n T extends Function ? T :\n T extends object ? DeepReadonlyObject :\n T;\n\ninterface DeepReadonlyArray extends ReadonlyArray> { }\n\ntype DeepReadonlyObject = {\n readonly [P in keyof T]: DeepReadonly;\n};\n\nexport type MaybeReadonly = T | Readonly;\n\n\n/**\n * Opposite of DeepReadonly,\n * makes everything mutable again.\n */\ntype DeepMutable = (\n T extends object\n ? {\n -readonly [K in keyof T]: (\n T[K] extends object\n ? DeepMutable\n : T[K]\n )\n }\n : never\n);\n\n/**\n * Can be used like 'keyof'\n * but only represents the string keys, not the Symbols or numbers.\n * @link https://stackoverflow.com/a/51808262/3443137\n */\nexport type StringKeys = Extract;\n\nexport type AnyKeys = { [P in keyof T]?: T[P] | any };\nexport interface AnyObject {\n [k: string]: any;\n}\n\n/**\n * @link https://dev.to/vborodulin/ts-how-to-override-properties-with-type-intersection-554l\n */\nexport type Override = Omit & T2;\n\n\n\nexport type ById = {\n [id: string]: T;\n};\n\n/**\n * Must be async to support async hashing like from the WebCrypto API.\n */\nexport type HashFunction = (input: string) => Promise;\n\nexport declare type QueryMatcher = (doc: DocType | DeepReadonly) => boolean;\n\n/**\n * To have a deterministic sorting, we cannot return 0,\n * we only return 1 or -1.\n * This ensures that we always end with the same output array, no mather of the\n * pre-sorting of the input array.\n */\nexport declare type DeterministicSortComparator = (a: DocType, b: DocType) => 1 | -1;\n\n/**\n * To test a storage, we need these\n * configuration values.\n */\nexport type RxTestStorage = {\n // can be used to setup async stuff\n readonly init?: () => any;\n // TODO remove name here, it can be read out already via getStorage().name\n readonly name: string;\n readonly getStorage: () => RxStorage;\n /**\n * Returns a storage that is used in performance tests.\n * For example in a browser it should return the storage with an IndexedDB based adapter,\n * while in node.js it must use the filesystem.\n */\n readonly getPerformanceStorage: () => {\n storage: RxStorage;\n /**\n * A description that describes the storage and setting.\n * For example 'dexie-native'.\n */\n description: string;\n };\n /**\n * True if the storage is able to\n * keep data after an instance is closed and opened again.\n */\n readonly hasPersistence: boolean;\n readonly hasMultiInstance: boolean;\n readonly hasAttachments: boolean;\n\n /**\n * Some storages likes the memory-synced storage,\n * are not able to provide a replication while guaranteeing\n * data integrity.\n */\n readonly hasReplication: boolean;\n\n /**\n * To make it possible to test alternative encryption plugins,\n * you can specify hasEncryption to signal\n * the test runner that the given storage already contains an\n * encryption plugin that should be used to test encryption tests.\n * Otherwise the encryption-crypto-js plugin will be tested.\n *\n * hasEncryption must contain a function that is able\n * to create a new password.\n */\n readonly hasEncryption?: () => Promise;\n};\n\n\n/**\n * The paths as strings-type of nested object\n * @link https://stackoverflow.com/a/58436959/3443137\n */\ntype Join = K extends string | number ?\n P extends string | number ?\n `${K}${'' extends P ? '' : '.'}${P}`\n : never : never;\n\nexport type Paths = [D] extends [never] ? never : T extends object ?\n { [K in keyof T]-?: K extends string | number ?\n `${K}` | (Paths extends infer R ? Join : never)\n : never\n }[keyof T] : '';\n\nexport type Leaves = [D] extends [never] ? never : T extends object ?\n { [K in keyof T]-?: Join> }[keyof T] : '';\ntype Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\n 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...0[]];\n"],"mappings":"","ignoreList":[]} \ No newline at end of file diff --git a/dist/esm/replication-protocol/downstream.js b/dist/esm/replication-protocol/downstream.js index 29d502ab3cb..9ff7b6c8a38 100644 --- a/dist/esm/replication-protocol/downstream.js +++ b/dist/esm/replication-protocol/downstream.js @@ -206,12 +206,15 @@ export async function startReplicationDownstream(state) { if (!isAssumedMasterEqualToForkState && assumedMaster && assumedMaster.docData._rev && forkStateFullDoc && forkStateFullDoc._meta[state.input.identifier] && getHeightOfRevision(forkStateFullDoc._rev) === forkStateFullDoc._meta[state.input.identifier]) { isAssumedMasterEqualToForkState = true; } - if (forkStateFullDoc && assumedMaster && isAssumedMasterEqualToForkState === false || forkStateFullDoc && !assumedMaster) { + if ((forkStateFullDoc && assumedMaster && isAssumedMasterEqualToForkState === false || forkStateFullDoc && !assumedMaster) && !(forkStateFullDoc._meta.o && forkStateFullDoc._meta.o.hash === identifierHash && forkStateFullDoc._meta.o._rev === getHeightOfRevision(forkStateFullDoc._rev))) { /** * We have a non-upstream-replicated * local write to the fork. - * This means we ignore the downstream of this document - * because anyway the upstream will first resolve the conflict. + * This means either we have to upstream the local + * doc data first, or it means that the fork state was + * synced from the master but the process exited before + * the metadata was written. + * @link https://github.com/pubkey/rxdb/pull/7804 */ return PROMISE_RESOLVE_VOID; } @@ -267,6 +270,17 @@ export async function startReplicationDownstream(state) { if (state.input.keepMeta && masterState._meta) { newForkState._meta = masterState._meta; } + + /** + * Tag the write with its origin so a later downstream run can tell + * "fork differs from assumed master" caused by a local write apart + * from one caused by a lost meta write. A local write bumps the + * revision height and voids the marker. + */ + newForkState._meta.o = { + _rev: !forkStateFullDoc ? 1 : getHeightOfRevision(forkStateFullDoc._rev) + 1, + hash: identifierHash + }; var forkWriteRow = { previous: forkStateFullDoc, document: newForkState diff --git a/dist/esm/replication-protocol/downstream.js.map b/dist/esm/replication-protocol/downstream.js.map index 8a3ad2dddea..6959d8b49f3 100644 --- a/dist/esm/replication-protocol/downstream.js.map +++ b/dist/esm/replication-protocol/downstream.js.map @@ -1 +1 @@ -{"version":3,"file":"downstream.js","names":["firstValueFrom","filter","mergeMap","newRxError","stackCheckpoints","appendToArray","createRevision","ensureNotFalsy","flatClone","getDefaultRevision","getHeightOfRevision","now","PROMISE_RESOLVE_VOID","getLastCheckpointDoc","setCheckpoint","stripAttachmentsDataFromMetaWriteRows","writeDocToDocState","getAssumedMasterState","getMetaWriteRow","startReplicationDownstream","state","input","initialCheckpoint","downstream","checkpointDoc","identifierHash","hashFunction","identifier","replicationHandler","timer","openTasks","addNewTask","task","stats","down","taskWithTime","time","push","streamQueue","then","useTasks","length","events","active","next","innerTaskWithTime","shift","lastTimeMasterChangesRequested","downstreamResyncOnce","downstreamProcessChanges","firstSyncDone","getValue","canceled","sub","masterChangeStream$","pipe","ev","up","s","subscribe","masterChangeStreamEmit","unsubscribe","checkpointQueue","lastCheckpoint","promises","downResult","masterChangesSince","pullBatchSize","documents","checkpoint","persistFromMaster","Promise","all","tasks","docsOfAllTasks","forEach","Error","persistenceQueue","nonPersistedFromMaster","docs","primaryPath","docData","docId","downDocsById","useCheckpoint","docIds","Object","keys","writeRowsToFork","writeRowsToForkById","writeRowsToMeta","useMetaWriteRows","forkInstance","findDocumentsById","currentForkStateList","assumedMasterState","currentForkState","Map","doc","set","map","forkStateFullDoc","get","forkStateDocData","hasAttachments","undefined","masterState","assumedMaster","metaDocument","isResolvedConflict","_rev","isAssumedMasterEqualToForkState","conflictHandler","realMasterState","newDocumentState","r","isEqual","_meta","areStatesExactlyEqual","newForkState","assign","_attachments","lwt","nextRevisionHeight","keepMeta","forkWriteRow","previous","document","bulkWrite","downstreamBulkWriteFlag","forkWriteResult","success","processed","error","status","writeError","metaInstance","metaWriteResult","id","documentId","catch","unhandledError"],"sources":["../../../src/replication-protocol/downstream.ts"],"sourcesContent":["import {\n firstValueFrom,\n filter,\n mergeMap\n} from 'rxjs';\nimport { newRxError } from '../rx-error.ts';\nimport { stackCheckpoints } from '../rx-storage-helper.ts';\nimport type {\n RxStorageInstanceReplicationState,\n BulkWriteRow,\n BulkWriteRowById,\n RxStorageReplicationMeta,\n RxDocumentData,\n ById,\n WithDeleted,\n DocumentsWithCheckpoint,\n WithDeletedAndAttachments\n} from '../types/index.d.ts';\nimport {\n appendToArray,\n createRevision,\n ensureNotFalsy,\n flatClone,\n getDefaultRevision,\n getHeightOfRevision,\n now,\n PROMISE_RESOLVE_VOID\n} from '../plugins/utils/index.ts';\nimport {\n getLastCheckpointDoc,\n setCheckpoint\n} from './checkpoint.ts';\nimport {\n stripAttachmentsDataFromMetaWriteRows,\n writeDocToDocState\n} from './helper.ts';\nimport {\n getAssumedMasterState,\n getMetaWriteRow\n} from './meta-instance.ts';\n\n/**\n * Writes all documents from the master to the fork.\n * The downstream has two operation modes\n * - Sync by iterating over the checkpoints via downstreamResyncOnce()\n * - Sync by listening to the changestream via downstreamProcessChanges()\n * We need this to be able to do initial syncs\n * and still can have fast event based sync when the client is not offline.\n */\nexport async function startReplicationDownstream(\n state: RxStorageInstanceReplicationState\n) {\n if (\n state.input.initialCheckpoint &&\n state.input.initialCheckpoint.downstream\n ) {\n const checkpointDoc = await getLastCheckpointDoc(state, 'down');\n if (!checkpointDoc) {\n await setCheckpoint(\n state,\n 'down',\n state.input.initialCheckpoint.downstream\n );\n }\n }\n\n const identifierHash = await state.input.hashFunction(state.input.identifier);\n const replicationHandler = state.input.replicationHandler;\n\n // used to detect which tasks etc can in it at which order.\n let timer = 0;\n\n\n type Task = DocumentsWithCheckpoint | 'RESYNC';\n type TaskWithTime = {\n time: number;\n task: Task;\n };\n const openTasks: TaskWithTime[] = [];\n\n\n function addNewTask(task: Task): void {\n state.stats.down.addNewTask = state.stats.down.addNewTask + 1;\n const taskWithTime = {\n time: timer++,\n task\n };\n openTasks.push(taskWithTime);\n state.streamQueue.down = state.streamQueue.down\n .then(() => {\n const useTasks: Task[] = [];\n while (openTasks.length > 0) {\n state.events.active.down.next(true);\n const innerTaskWithTime = ensureNotFalsy(openTasks.shift());\n\n /**\n * If the task came in before the last time we started the pull\n * from the master, then we can drop the task.\n */\n if (innerTaskWithTime.time < lastTimeMasterChangesRequested) {\n continue;\n }\n\n if (innerTaskWithTime.task === 'RESYNC') {\n if (useTasks.length === 0) {\n useTasks.push(innerTaskWithTime.task);\n break;\n } else {\n break;\n }\n }\n\n useTasks.push(innerTaskWithTime.task);\n }\n if (useTasks.length === 0) {\n return;\n }\n\n if (useTasks[0] === 'RESYNC') {\n return downstreamResyncOnce();\n } else {\n return downstreamProcessChanges(useTasks);\n }\n }).then(() => {\n state.events.active.down.next(false);\n if (\n !state.firstSyncDone.down.getValue() &&\n !state.events.canceled.getValue()\n ) {\n state.firstSyncDone.down.next(true);\n }\n });\n }\n addNewTask('RESYNC');\n\n /**\n * If a write on the master happens, we have to trigger the downstream.\n * Only do this if not canceled yet, otherwise firstValueFrom errors\n * when running on a completed observable.\n */\n if (!state.events.canceled.getValue()) {\n const sub = replicationHandler\n .masterChangeStream$\n .pipe(\n mergeMap(async (ev) => {\n /**\n * While a push is running, we have to delay all incoming\n * events from the server to not mix up the replication state.\n */\n await firstValueFrom(\n state.events.active.up.pipe(filter(s => !s))\n );\n return ev;\n })\n )\n .subscribe((task: Task) => {\n state.stats.down.masterChangeStreamEmit = state.stats.down.masterChangeStreamEmit + 1;\n addNewTask(task);\n });\n firstValueFrom(\n state.events.canceled.pipe(\n filter(canceled => !!canceled)\n )\n ).then(() => sub.unsubscribe());\n }\n\n\n /**\n * For faster performance, we directly start each write\n * and then await all writes at the end.\n */\n let lastTimeMasterChangesRequested: number = -1;\n async function downstreamResyncOnce() {\n state.stats.down.downstreamResyncOnce = state.stats.down.downstreamResyncOnce + 1;\n if (state.events.canceled.getValue()) {\n return;\n }\n\n state.checkpointQueue = state.checkpointQueue.then(() => getLastCheckpointDoc(state, 'down'));\n let lastCheckpoint: CheckpointType = await state.checkpointQueue;\n\n\n const promises: Promise[] = [];\n while (!state.events.canceled.getValue()) {\n lastTimeMasterChangesRequested = timer++;\n const downResult = await replicationHandler.masterChangesSince(\n lastCheckpoint,\n state.input.pullBatchSize\n );\n\n if (downResult.documents.length === 0) {\n break;\n }\n\n lastCheckpoint = stackCheckpoints([lastCheckpoint, downResult.checkpoint]);\n\n promises.push(\n persistFromMaster(\n downResult.documents,\n lastCheckpoint\n )\n );\n\n /**\n * By definition we stop pull when the pulled documents\n * do not fill up the pullBatchSize because we\n * can assume that the remote has no more documents.\n */\n if (downResult.documents.length < state.input.pullBatchSize) {\n break;\n }\n\n }\n await Promise.all(promises);\n }\n\n\n function downstreamProcessChanges(tasks: Task[]) {\n state.stats.down.downstreamProcessChanges = state.stats.down.downstreamProcessChanges + 1;\n const docsOfAllTasks: WithDeleted[] = [];\n let lastCheckpoint: CheckpointType | undefined = null as any;\n\n tasks.forEach(task => {\n if (task === 'RESYNC') {\n throw new Error('SNH');\n }\n appendToArray(docsOfAllTasks, task.documents);\n lastCheckpoint = stackCheckpoints([lastCheckpoint, task.checkpoint]);\n });\n return persistFromMaster(\n docsOfAllTasks,\n ensureNotFalsy(lastCheckpoint)\n );\n }\n\n\n /**\n * It can happen that the calls to masterChangesSince() or the changeStream()\n * are way faster then how fast the documents can be persisted.\n * Therefore we merge all incoming downResults into the nonPersistedFromMaster object\n * and process them together if possible.\n * This often bundles up single writes and improves performance\n * by processing the documents in bulks.\n */\n let persistenceQueue = PROMISE_RESOLVE_VOID;\n const nonPersistedFromMaster: {\n checkpoint?: CheckpointType;\n docs: ById>;\n } = {\n docs: {}\n };\n\n function persistFromMaster(\n docs: WithDeleted[],\n checkpoint: CheckpointType\n ): Promise {\n const primaryPath = state.primaryPath;\n state.stats.down.persistFromMaster = state.stats.down.persistFromMaster + 1;\n\n /**\n * Add the new docs to the non-persistent list\n */\n docs.forEach(docData => {\n const docId: string = (docData as any)[primaryPath];\n nonPersistedFromMaster.docs[docId] = docData;\n });\n nonPersistedFromMaster.checkpoint = checkpoint;\n\n /**\n * Run in the queue\n * with all open documents from nonPersistedFromMaster.\n */\n persistenceQueue = persistenceQueue.then(() => {\n\n const downDocsById: ById> = nonPersistedFromMaster.docs;\n nonPersistedFromMaster.docs = {};\n const useCheckpoint = nonPersistedFromMaster.checkpoint;\n const docIds = Object.keys(downDocsById);\n\n if (\n state.events.canceled.getValue() ||\n docIds.length === 0\n ) {\n return PROMISE_RESOLVE_VOID;\n }\n\n const writeRowsToFork: BulkWriteRow[] = [];\n const writeRowsToForkById: ById> = {};\n const writeRowsToMeta: BulkWriteRowById> = {};\n const useMetaWriteRows: BulkWriteRow>[] = [];\n\n return Promise.all([\n state.input.forkInstance.findDocumentsById(docIds, true),\n getAssumedMasterState(\n state,\n docIds\n )\n ]).then(([\n currentForkStateList,\n assumedMasterState\n ]) => {\n const currentForkState = new Map>();\n currentForkStateList.forEach(doc => currentForkState.set((doc as any)[primaryPath], doc));\n return Promise.all(\n docIds.map(async (docId) => {\n const forkStateFullDoc: RxDocumentData | undefined = currentForkState.get(docId);\n const forkStateDocData: WithDeletedAndAttachments | undefined = forkStateFullDoc\n ? writeDocToDocState(forkStateFullDoc, state.hasAttachments, false)\n : undefined\n ;\n const masterState = downDocsById[docId];\n const assumedMaster = assumedMasterState[docId];\n\n if (\n assumedMaster &&\n forkStateFullDoc &&\n assumedMaster.metaDocument.isResolvedConflict === forkStateFullDoc._rev\n ) {\n /**\n * The current fork state represents a resolved conflict\n * that first must be send to the master in the upstream.\n * All conflicts are resolved by the upstream.\n */\n // return PROMISE_RESOLVE_VOID;\n await state.streamQueue.up;\n }\n\n let isAssumedMasterEqualToForkState = !assumedMaster || !forkStateDocData ?\n false :\n await state.input.conflictHandler({\n realMasterState: assumedMaster.docData,\n newDocumentState: forkStateDocData\n }, 'downstream-check-if-equal-0').then(r => r.isEqual);\n if (\n !isAssumedMasterEqualToForkState &&\n (\n assumedMaster &&\n (assumedMaster.docData as any)._rev &&\n forkStateFullDoc &&\n forkStateFullDoc._meta[state.input.identifier] &&\n getHeightOfRevision(forkStateFullDoc._rev) === forkStateFullDoc._meta[state.input.identifier]\n )\n ) {\n isAssumedMasterEqualToForkState = true;\n }\n if (\n (\n forkStateFullDoc &&\n assumedMaster &&\n isAssumedMasterEqualToForkState === false\n ) ||\n (\n forkStateFullDoc && !assumedMaster\n )\n ) {\n /**\n * We have a non-upstream-replicated\n * local write to the fork.\n * This means we ignore the downstream of this document\n * because anyway the upstream will first resolve the conflict.\n */\n return PROMISE_RESOLVE_VOID;\n }\n\n const areStatesExactlyEqual = !forkStateDocData\n ? false\n : await state.input.conflictHandler(\n {\n realMasterState: masterState,\n newDocumentState: forkStateDocData\n },\n 'downstream-check-if-equal-1'\n ).then(r => r.isEqual);\n if (\n forkStateDocData &&\n areStatesExactlyEqual\n ) {\n /**\n * Document states are exactly equal.\n * This can happen when the replication is shut down\n * unexpected like when the user goes offline.\n *\n * Only when the assumedMaster is different from the forkState,\n * we have to patch the document in the meta instance.\n */\n if (\n !assumedMaster ||\n isAssumedMasterEqualToForkState === false\n ) {\n useMetaWriteRows.push(\n await getMetaWriteRow(\n state,\n forkStateDocData,\n assumedMaster ? assumedMaster.metaDocument : undefined\n )\n );\n }\n return PROMISE_RESOLVE_VOID;\n }\n\n /**\n * All other master states need to be written to the forkInstance\n * and metaInstance.\n */\n const newForkState = Object.assign(\n {},\n masterState,\n forkStateFullDoc ? {\n _meta: flatClone(forkStateFullDoc._meta),\n _attachments: state.hasAttachments && masterState._attachments ? masterState._attachments : {},\n _rev: getDefaultRevision()\n } : {\n _meta: {\n lwt: now()\n },\n _rev: getDefaultRevision(),\n _attachments: state.hasAttachments && masterState._attachments ? masterState._attachments : {}\n }\n );\n /**\n * If the remote works with revisions,\n * we store the height of the next fork-state revision\n * inside of the documents meta data.\n * By doing so we can filter it out in the upstream\n * and detect the document as being equal to master or not.\n * This is used for example in the CouchDB replication plugin.\n */\n if ((masterState as any)._rev) {\n const nextRevisionHeight = !forkStateFullDoc ? 1 : getHeightOfRevision(forkStateFullDoc._rev) + 1;\n newForkState._meta[state.input.identifier] = nextRevisionHeight;\n if (state.input.keepMeta) {\n newForkState._rev = (masterState as any)._rev;\n }\n }\n if (\n state.input.keepMeta &&\n (masterState as any)._meta\n ) {\n newForkState._meta = (masterState as any)._meta;\n }\n\n const forkWriteRow = {\n previous: forkStateFullDoc,\n document: newForkState\n };\n\n forkWriteRow.document._rev = forkWriteRow.document._rev ? forkWriteRow.document._rev : createRevision(\n identifierHash,\n forkWriteRow.previous\n );\n writeRowsToFork.push(forkWriteRow);\n writeRowsToForkById[docId] = forkWriteRow;\n writeRowsToMeta[docId] = await getMetaWriteRow(\n state,\n masterState,\n assumedMaster ? assumedMaster.metaDocument : undefined\n );\n })\n );\n }).then(async () => {\n if (writeRowsToFork.length > 0) {\n return state.input.forkInstance.bulkWrite(\n writeRowsToFork,\n await state.downstreamBulkWriteFlag\n ).then((forkWriteResult) => {\n forkWriteResult.success.forEach(doc => {\n const docId = (doc as any)[primaryPath];\n state.events.processed.down.next(writeRowsToForkById[docId]);\n useMetaWriteRows.push(writeRowsToMeta[docId]);\n });\n forkWriteResult.error.forEach(error => {\n /**\n * We do not have to care about downstream conflict errors here\n * because on conflict, it will be solved locally and result in another write.\n */\n if (error.status === 409) {\n return;\n }\n // other non-conflict errors must be handled\n state.events.error.next(newRxError('RC_PULL', {\n writeError: error\n }));\n });\n });\n }\n }).then(() => {\n if (useMetaWriteRows.length > 0) {\n return state.input.metaInstance.bulkWrite(\n stripAttachmentsDataFromMetaWriteRows(state, useMetaWriteRows),\n 'replication-down-write-meta'\n ).then(metaWriteResult => {\n metaWriteResult.error\n .forEach(writeError => {\n state.events.error.next(newRxError('RC_PULL', {\n id: writeError.documentId,\n writeError\n }));\n });\n });\n }\n }).then(() => {\n /**\n * For better performance we do not await checkpoint writes,\n * but to ensure order on parallel checkpoint writes,\n * we have to use a queue.\n */\n setCheckpoint(\n state,\n 'down',\n useCheckpoint\n );\n });\n }).catch(unhandledError => state.events.error.next(unhandledError));\n return persistenceQueue;\n }\n}\n"],"mappings":"AAAA,SACIA,cAAc,EACdC,MAAM,EACNC,QAAQ,QACL,MAAM;AACb,SAASC,UAAU,QAAQ,gBAAgB;AAC3C,SAASC,gBAAgB,QAAQ,yBAAyB;AAY1D,SACIC,aAAa,EACbC,cAAc,EACdC,cAAc,EACdC,SAAS,EACTC,kBAAkB,EAClBC,mBAAmB,EACnBC,GAAG,EACHC,oBAAoB,QACjB,2BAA2B;AAClC,SACIC,oBAAoB,EACpBC,aAAa,QACV,iBAAiB;AACxB,SACIC,qCAAqC,EACrCC,kBAAkB,QACf,aAAa;AACpB,SACIC,qBAAqB,EACrBC,eAAe,QACZ,oBAAoB;;AAE3B;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,OAAO,eAAeC,0BAA0BA,CAC5CC,KAAmD,EACrD;EACE,IACIA,KAAK,CAACC,KAAK,CAACC,iBAAiB,IAC7BF,KAAK,CAACC,KAAK,CAACC,iBAAiB,CAACC,UAAU,EAC1C;IACE,IAAMC,aAAa,GAAG,MAAMX,oBAAoB,CAACO,KAAK,EAAE,MAAM,CAAC;IAC/D,IAAI,CAACI,aAAa,EAAE;MAChB,MAAMV,aAAa,CACfM,KAAK,EACL,MAAM,EACNA,KAAK,CAACC,KAAK,CAACC,iBAAiB,CAACC,UAClC,CAAC;IACL;EACJ;EAEA,IAAME,cAAc,GAAG,MAAML,KAAK,CAACC,KAAK,CAACK,YAAY,CAACN,KAAK,CAACC,KAAK,CAACM,UAAU,CAAC;EAC7E,IAAMC,kBAAkB,GAAGR,KAAK,CAACC,KAAK,CAACO,kBAAkB;;EAEzD;EACA,IAAIC,KAAK,GAAG,CAAC;EAQb,IAAMC,SAAyB,GAAG,EAAE;EAGpC,SAASC,UAAUA,CAACC,IAAU,EAAQ;IAClCZ,KAAK,CAACa,KAAK,CAACC,IAAI,CAACH,UAAU,GAAGX,KAAK,CAACa,KAAK,CAACC,IAAI,CAACH,UAAU,GAAG,CAAC;IAC7D,IAAMI,YAAY,GAAG;MACjBC,IAAI,EAAEP,KAAK,EAAE;MACbG;IACJ,CAAC;IACDF,SAAS,CAACO,IAAI,CAACF,YAAY,CAAC;IAC5Bf,KAAK,CAACkB,WAAW,CAACJ,IAAI,GAAGd,KAAK,CAACkB,WAAW,CAACJ,IAAI,CAC1CK,IAAI,CAAC,MAAM;MACR,IAAMC,QAAgB,GAAG,EAAE;MAC3B,OAAOV,SAAS,CAACW,MAAM,GAAG,CAAC,EAAE;QACzBrB,KAAK,CAACsB,MAAM,CAACC,MAAM,CAACT,IAAI,CAACU,IAAI,CAAC,IAAI,CAAC;QACnC,IAAMC,iBAAiB,GAAGtC,cAAc,CAACuB,SAAS,CAACgB,KAAK,CAAC,CAAC,CAAC;;QAE3D;AACpB;AACA;AACA;QACoB,IAAID,iBAAiB,CAACT,IAAI,GAAGW,8BAA8B,EAAE;UACzD;QACJ;QAEA,IAAIF,iBAAiB,CAACb,IAAI,KAAK,QAAQ,EAAE;UACrC,IAAIQ,QAAQ,CAACC,MAAM,KAAK,CAAC,EAAE;YACvBD,QAAQ,CAACH,IAAI,CAACQ,iBAAiB,CAACb,IAAI,CAAC;YACrC;UACJ,CAAC,MAAM;YACH;UACJ;QACJ;QAEAQ,QAAQ,CAACH,IAAI,CAACQ,iBAAiB,CAACb,IAAI,CAAC;MACzC;MACA,IAAIQ,QAAQ,CAACC,MAAM,KAAK,CAAC,EAAE;QACvB;MACJ;MAEA,IAAID,QAAQ,CAAC,CAAC,CAAC,KAAK,QAAQ,EAAE;QAC1B,OAAOQ,oBAAoB,CAAC,CAAC;MACjC,CAAC,MAAM;QACH,OAAOC,wBAAwB,CAACT,QAAQ,CAAC;MAC7C;IACJ,CAAC,CAAC,CAACD,IAAI,CAAC,MAAM;MACVnB,KAAK,CAACsB,MAAM,CAACC,MAAM,CAACT,IAAI,CAACU,IAAI,CAAC,KAAK,CAAC;MACpC,IACI,CAACxB,KAAK,CAAC8B,aAAa,CAAChB,IAAI,CAACiB,QAAQ,CAAC,CAAC,IACpC,CAAC/B,KAAK,CAACsB,MAAM,CAACU,QAAQ,CAACD,QAAQ,CAAC,CAAC,EACnC;QACE/B,KAAK,CAAC8B,aAAa,CAAChB,IAAI,CAACU,IAAI,CAAC,IAAI,CAAC;MACvC;IACJ,CAAC,CAAC;EACV;EACAb,UAAU,CAAC,QAAQ,CAAC;;EAEpB;AACJ;AACA;AACA;AACA;EACI,IAAI,CAACX,KAAK,CAACsB,MAAM,CAACU,QAAQ,CAACD,QAAQ,CAAC,CAAC,EAAE;IACnC,IAAME,GAAG,GAAGzB,kBAAkB,CACzB0B,mBAAmB,CACnBC,IAAI,CACDrD,QAAQ,CAAC,MAAOsD,EAAE,IAAK;MACnB;AACpB;AACA;AACA;MACoB,MAAMxD,cAAc,CAChBoB,KAAK,CAACsB,MAAM,CAACC,MAAM,CAACc,EAAE,CAACF,IAAI,CAACtD,MAAM,CAACyD,CAAC,IAAI,CAACA,CAAC,CAAC,CAC/C,CAAC;MACD,OAAOF,EAAE;IACb,CAAC,CACL,CAAC,CACAG,SAAS,CAAE3B,IAAU,IAAK;MACvBZ,KAAK,CAACa,KAAK,CAACC,IAAI,CAAC0B,sBAAsB,GAAGxC,KAAK,CAACa,KAAK,CAACC,IAAI,CAAC0B,sBAAsB,GAAG,CAAC;MACrF7B,UAAU,CAACC,IAAI,CAAC;IACpB,CAAC,CAAC;IACNhC,cAAc,CACVoB,KAAK,CAACsB,MAAM,CAACU,QAAQ,CAACG,IAAI,CACtBtD,MAAM,CAACmD,QAAQ,IAAI,CAAC,CAACA,QAAQ,CACjC,CACJ,CAAC,CAACb,IAAI,CAAC,MAAMc,GAAG,CAACQ,WAAW,CAAC,CAAC,CAAC;EACnC;;EAGA;AACJ;AACA;AACA;EACI,IAAId,8BAAsC,GAAG,CAAC,CAAC;EAC/C,eAAeC,oBAAoBA,CAAA,EAAG;IAClC5B,KAAK,CAACa,KAAK,CAACC,IAAI,CAACc,oBAAoB,GAAG5B,KAAK,CAACa,KAAK,CAACC,IAAI,CAACc,oBAAoB,GAAG,CAAC;IACjF,IAAI5B,KAAK,CAACsB,MAAM,CAACU,QAAQ,CAACD,QAAQ,CAAC,CAAC,EAAE;MAClC;IACJ;IAEA/B,KAAK,CAAC0C,eAAe,GAAG1C,KAAK,CAAC0C,eAAe,CAACvB,IAAI,CAAC,MAAM1B,oBAAoB,CAACO,KAAK,EAAE,MAAM,CAAC,CAAC;IAC7F,IAAI2C,cAA8B,GAAG,MAAM3C,KAAK,CAAC0C,eAAe;IAGhE,IAAME,QAAwB,GAAG,EAAE;IACnC,OAAO,CAAC5C,KAAK,CAACsB,MAAM,CAACU,QAAQ,CAACD,QAAQ,CAAC,CAAC,EAAE;MACtCJ,8BAA8B,GAAGlB,KAAK,EAAE;MACxC,IAAMoC,UAAU,GAAG,MAAMrC,kBAAkB,CAACsC,kBAAkB,CAC1DH,cAAc,EACd3C,KAAK,CAACC,KAAK,CAAC8C,aAChB,CAAC;MAED,IAAIF,UAAU,CAACG,SAAS,CAAC3B,MAAM,KAAK,CAAC,EAAE;QACnC;MACJ;MAEAsB,cAAc,GAAG3D,gBAAgB,CAAC,CAAC2D,cAAc,EAAEE,UAAU,CAACI,UAAU,CAAC,CAAC;MAE1EL,QAAQ,CAAC3B,IAAI,CACTiC,iBAAiB,CACbL,UAAU,CAACG,SAAS,EACpBL,cACJ,CACJ,CAAC;;MAED;AACZ;AACA;AACA;AACA;MACY,IAAIE,UAAU,CAACG,SAAS,CAAC3B,MAAM,GAAGrB,KAAK,CAACC,KAAK,CAAC8C,aAAa,EAAE;QACzD;MACJ;IAEJ;IACA,MAAMI,OAAO,CAACC,GAAG,CAACR,QAAQ,CAAC;EAC/B;EAGA,SAASf,wBAAwBA,CAACwB,KAAa,EAAE;IAC7CrD,KAAK,CAACa,KAAK,CAACC,IAAI,CAACe,wBAAwB,GAAG7B,KAAK,CAACa,KAAK,CAACC,IAAI,CAACe,wBAAwB,GAAG,CAAC;IACzF,IAAMyB,cAAwC,GAAG,EAAE;IACnD,IAAIX,cAA0C,GAAG,IAAW;IAE5DU,KAAK,CAACE,OAAO,CAAC3C,IAAI,IAAI;MAClB,IAAIA,IAAI,KAAK,QAAQ,EAAE;QACnB,MAAM,IAAI4C,KAAK,CAAC,KAAK,CAAC;MAC1B;MACAvE,aAAa,CAACqE,cAAc,EAAE1C,IAAI,CAACoC,SAAS,CAAC;MAC7CL,cAAc,GAAG3D,gBAAgB,CAAC,CAAC2D,cAAc,EAAE/B,IAAI,CAACqC,UAAU,CAAC,CAAC;IACxE,CAAC,CAAC;IACF,OAAOC,iBAAiB,CACpBI,cAAc,EACdnE,cAAc,CAACwD,cAAc,CACjC,CAAC;EACL;;EAGA;AACJ;AACA;AACA;AACA;AACA;AACA;AACA;EACI,IAAIc,gBAAgB,GAAGjE,oBAAoB;EAC3C,IAAMkE,sBAGL,GAAG;IACAC,IAAI,EAAE,CAAC;EACX,CAAC;EAED,SAAST,iBAAiBA,CACtBS,IAA8B,EAC9BV,UAA0B,EACb;IACb,IAAMW,WAAW,GAAG5D,KAAK,CAAC4D,WAAW;IACrC5D,KAAK,CAACa,KAAK,CAACC,IAAI,CAACoC,iBAAiB,GAAGlD,KAAK,CAACa,KAAK,CAACC,IAAI,CAACoC,iBAAiB,GAAG,CAAC;;IAE3E;AACR;AACA;IACQS,IAAI,CAACJ,OAAO,CAACM,OAAO,IAAI;MACpB,IAAMC,KAAa,GAAID,OAAO,CAASD,WAAW,CAAC;MACnDF,sBAAsB,CAACC,IAAI,CAACG,KAAK,CAAC,GAAGD,OAAO;IAChD,CAAC,CAAC;IACFH,sBAAsB,CAACT,UAAU,GAAGA,UAAU;;IAE9C;AACR;AACA;AACA;IACQQ,gBAAgB,GAAGA,gBAAgB,CAACtC,IAAI,CAAC,MAAM;MAE3C,IAAM4C,YAAwD,GAAGL,sBAAsB,CAACC,IAAI;MAC5FD,sBAAsB,CAACC,IAAI,GAAG,CAAC,CAAC;MAChC,IAAMK,aAAa,GAAGN,sBAAsB,CAACT,UAAU;MACvD,IAAMgB,MAAM,GAAGC,MAAM,CAACC,IAAI,CAACJ,YAAY,CAAC;MAExC,IACI/D,KAAK,CAACsB,MAAM,CAACU,QAAQ,CAACD,QAAQ,CAAC,CAAC,IAChCkC,MAAM,CAAC5C,MAAM,KAAK,CAAC,EACrB;QACE,OAAO7B,oBAAoB;MAC/B;MAEA,IAAM4E,eAA0C,GAAG,EAAE;MACrD,IAAMC,mBAAkD,GAAG,CAAC,CAAC;MAC7D,IAAMC,eAAsF,GAAG,CAAC,CAAC;MACjG,IAAMC,gBAAqF,GAAG,EAAE;MAEhG,OAAOpB,OAAO,CAACC,GAAG,CAAC,CACfpD,KAAK,CAACC,KAAK,CAACuE,YAAY,CAACC,iBAAiB,CAACR,MAAM,EAAE,IAAI,CAAC,EACxDpE,qBAAqB,CACjBG,KAAK,EACLiE,MACJ,CAAC,CACJ,CAAC,CAAC9C,IAAI,CAAC,CAAC,CACLuD,oBAAoB,EACpBC,kBAAkB,CACrB,KAAK;QACF,IAAMC,gBAAgB,GAAG,IAAIC,GAAG,CAAoC,CAAC;QACrEH,oBAAoB,CAACnB,OAAO,CAACuB,GAAG,IAAIF,gBAAgB,CAACG,GAAG,CAAED,GAAG,CAASlB,WAAW,CAAC,EAAEkB,GAAG,CAAC,CAAC;QACzF,OAAO3B,OAAO,CAACC,GAAG,CACda,MAAM,CAACe,GAAG,CAAC,MAAOlB,KAAK,IAAK;UACxB,IAAMmB,gBAAuD,GAAGL,gBAAgB,CAACM,GAAG,CAACpB,KAAK,CAAC;UAC3F,IAAMqB,gBAAkE,GAAGF,gBAAgB,GACrFrF,kBAAkB,CAACqF,gBAAgB,EAAEjF,KAAK,CAACoF,cAAc,EAAE,KAAK,CAAC,GACjEC,SAAS;UAEf,IAAMC,WAAW,GAAGvB,YAAY,CAACD,KAAK,CAAC;UACvC,IAAMyB,aAAa,GAAGZ,kBAAkB,CAACb,KAAK,CAAC;UAE/C,IACIyB,aAAa,IACbN,gBAAgB,IAChBM,aAAa,CAACC,YAAY,CAACC,kBAAkB,KAAKR,gBAAgB,CAACS,IAAI,EACzE;YACE;AAC5B;AACA;AACA;AACA;YAC4B;YACA,MAAM1F,KAAK,CAACkB,WAAW,CAACmB,EAAE;UAC9B;UAEA,IAAIsD,+BAA+B,GAAG,CAACJ,aAAa,IAAI,CAACJ,gBAAgB,GACrE,KAAK,GACL,MAAMnF,KAAK,CAACC,KAAK,CAAC2F,eAAe,CAAC;YAC9BC,eAAe,EAAEN,aAAa,CAAC1B,OAAO;YACtCiC,gBAAgB,EAAEX;UACtB,CAAC,EAAE,6BAA6B,CAAC,CAAChE,IAAI,CAAC4E,CAAC,IAAIA,CAAC,CAACC,OAAO,CAAC;UAC1D,IACI,CAACL,+BAA+B,IAE5BJ,aAAa,IACZA,aAAa,CAAC1B,OAAO,CAAS6B,IAAI,IACnCT,gBAAgB,IAChBA,gBAAgB,CAACgB,KAAK,CAACjG,KAAK,CAACC,KAAK,CAACM,UAAU,CAAC,IAC9CjB,mBAAmB,CAAC2F,gBAAgB,CAACS,IAAI,CAAC,KAAKT,gBAAgB,CAACgB,KAAK,CAACjG,KAAK,CAACC,KAAK,CAACM,UAAU,CAC/F,EACH;YACEoF,+BAA+B,GAAG,IAAI;UAC1C;UACA,IAEQV,gBAAgB,IAChBM,aAAa,IACbI,+BAA+B,KAAK,KAAK,IAGzCV,gBAAgB,IAAI,CAACM,aACxB,EACH;YACE;AAC5B;AACA;AACA;AACA;AACA;YAC4B,OAAO/F,oBAAoB;UAC/B;UAEA,IAAM0G,qBAAqB,GAAG,CAACf,gBAAgB,GACzC,KAAK,GACL,MAAMnF,KAAK,CAACC,KAAK,CAAC2F,eAAe,CAC/B;YACIC,eAAe,EAAEP,WAAW;YAC5BQ,gBAAgB,EAAEX;UACtB,CAAC,EACD,6BACJ,CAAC,CAAChE,IAAI,CAAC4E,CAAC,IAAIA,CAAC,CAACC,OAAO,CAAC;UAC1B,IACIb,gBAAgB,IAChBe,qBAAqB,EACvB;YACE;AAC5B;AACA;AACA;AACA;AACA;AACA;AACA;YAC4B,IACI,CAACX,aAAa,IACdI,+BAA+B,KAAK,KAAK,EAC3C;cACEpB,gBAAgB,CAACtD,IAAI,CACjB,MAAMnB,eAAe,CACjBE,KAAK,EACLmF,gBAAgB,EAChBI,aAAa,GAAGA,aAAa,CAACC,YAAY,GAAGH,SACjD,CACJ,CAAC;YACL;YACA,OAAO7F,oBAAoB;UAC/B;;UAEA;AACxB;AACA;AACA;UACwB,IAAM2G,YAAY,GAAGjC,MAAM,CAACkC,MAAM,CAC9B,CAAC,CAAC,EACFd,WAAW,EACXL,gBAAgB,GAAG;YACfgB,KAAK,EAAE7G,SAAS,CAAC6F,gBAAgB,CAACgB,KAAK,CAAC;YACxCI,YAAY,EAAErG,KAAK,CAACoF,cAAc,IAAIE,WAAW,CAACe,YAAY,GAAGf,WAAW,CAACe,YAAY,GAAG,CAAC,CAAC;YAC9FX,IAAI,EAAErG,kBAAkB,CAAC;UAC7B,CAAC,GAAG;YACA4G,KAAK,EAAE;cACHK,GAAG,EAAE/G,GAAG,CAAC;YACb,CAAC;YACDmG,IAAI,EAAErG,kBAAkB,CAAC,CAAC;YAC1BgH,YAAY,EAAErG,KAAK,CAACoF,cAAc,IAAIE,WAAW,CAACe,YAAY,GAAGf,WAAW,CAACe,YAAY,GAAG,CAAC;UACjG,CACJ,CAAC;UACD;AACxB;AACA;AACA;AACA;AACA;AACA;AACA;UACwB,IAAKf,WAAW,CAASI,IAAI,EAAE;YAC3B,IAAMa,kBAAkB,GAAG,CAACtB,gBAAgB,GAAG,CAAC,GAAG3F,mBAAmB,CAAC2F,gBAAgB,CAACS,IAAI,CAAC,GAAG,CAAC;YACjGS,YAAY,CAACF,KAAK,CAACjG,KAAK,CAACC,KAAK,CAACM,UAAU,CAAC,GAAGgG,kBAAkB;YAC/D,IAAIvG,KAAK,CAACC,KAAK,CAACuG,QAAQ,EAAE;cACtBL,YAAY,CAACT,IAAI,GAAIJ,WAAW,CAASI,IAAI;YACjD;UACJ;UACA,IACI1F,KAAK,CAACC,KAAK,CAACuG,QAAQ,IACnBlB,WAAW,CAASW,KAAK,EAC5B;YACEE,YAAY,CAACF,KAAK,GAAIX,WAAW,CAASW,KAAK;UACnD;UAEA,IAAMQ,YAAY,GAAG;YACjBC,QAAQ,EAAEzB,gBAAgB;YAC1B0B,QAAQ,EAAER;UACd,CAAC;UAEDM,YAAY,CAACE,QAAQ,CAACjB,IAAI,GAAGe,YAAY,CAACE,QAAQ,CAACjB,IAAI,GAAGe,YAAY,CAACE,QAAQ,CAACjB,IAAI,GAAGxG,cAAc,CACjGmB,cAAc,EACdoG,YAAY,CAACC,QACjB,CAAC;UACDtC,eAAe,CAACnD,IAAI,CAACwF,YAAY,CAAC;UAClCpC,mBAAmB,CAACP,KAAK,CAAC,GAAG2C,YAAY;UACzCnC,eAAe,CAACR,KAAK,CAAC,GAAG,MAAMhE,eAAe,CAC1CE,KAAK,EACLsF,WAAW,EACXC,aAAa,GAAGA,aAAa,CAACC,YAAY,GAAGH,SACjD,CAAC;QACL,CAAC,CACL,CAAC;MACL,CAAC,CAAC,CAAClE,IAAI,CAAC,YAAY;QAChB,IAAIiD,eAAe,CAAC/C,MAAM,GAAG,CAAC,EAAE;UAC5B,OAAOrB,KAAK,CAACC,KAAK,CAACuE,YAAY,CAACoC,SAAS,CACrCxC,eAAe,EACf,MAAMpE,KAAK,CAAC6G,uBAChB,CAAC,CAAC1F,IAAI,CAAE2F,eAAe,IAAK;YACxBA,eAAe,CAACC,OAAO,CAACxD,OAAO,CAACuB,GAAG,IAAI;cACnC,IAAMhB,KAAK,GAAIgB,GAAG,CAASlB,WAAW,CAAC;cACvC5D,KAAK,CAACsB,MAAM,CAAC0F,SAAS,CAAClG,IAAI,CAACU,IAAI,CAAC6C,mBAAmB,CAACP,KAAK,CAAC,CAAC;cAC5DS,gBAAgB,CAACtD,IAAI,CAACqD,eAAe,CAACR,KAAK,CAAC,CAAC;YACjD,CAAC,CAAC;YACFgD,eAAe,CAACG,KAAK,CAAC1D,OAAO,CAAC0D,KAAK,IAAI;cACnC;AAC5B;AACA;AACA;cAC4B,IAAIA,KAAK,CAACC,MAAM,KAAK,GAAG,EAAE;gBACtB;cACJ;cACA;cACAlH,KAAK,CAACsB,MAAM,CAAC2F,KAAK,CAACzF,IAAI,CAACzC,UAAU,CAAC,SAAS,EAAE;gBAC1CoI,UAAU,EAAEF;cAChB,CAAC,CAAC,CAAC;YACP,CAAC,CAAC;UACN,CAAC,CAAC;QACN;MACJ,CAAC,CAAC,CAAC9F,IAAI,CAAC,MAAM;QACV,IAAIoD,gBAAgB,CAAClD,MAAM,GAAG,CAAC,EAAE;UAC7B,OAAOrB,KAAK,CAACC,KAAK,CAACmH,YAAY,CAACR,SAAS,CACrCjH,qCAAqC,CAACK,KAAK,EAAEuE,gBAAgB,CAAC,EAC9D,6BACJ,CAAC,CAACpD,IAAI,CAACkG,eAAe,IAAI;YACtBA,eAAe,CAACJ,KAAK,CAChB1D,OAAO,CAAC4D,UAAU,IAAI;cACnBnH,KAAK,CAACsB,MAAM,CAAC2F,KAAK,CAACzF,IAAI,CAACzC,UAAU,CAAC,SAAS,EAAE;gBAC1CuI,EAAE,EAAEH,UAAU,CAACI,UAAU;gBACzBJ;cACJ,CAAC,CAAC,CAAC;YACP,CAAC,CAAC;UACV,CAAC,CAAC;QACN;MACJ,CAAC,CAAC,CAAChG,IAAI,CAAC,MAAM;QACV;AAChB;AACA;AACA;AACA;QACgBzB,aAAa,CACTM,KAAK,EACL,MAAM,EACNgE,aACJ,CAAC;MACL,CAAC,CAAC;IACN,CAAC,CAAC,CAACwD,KAAK,CAACC,cAAc,IAAIzH,KAAK,CAACsB,MAAM,CAAC2F,KAAK,CAACzF,IAAI,CAACiG,cAAc,CAAC,CAAC;IACnE,OAAOhE,gBAAgB;EAC3B;AACJ","ignoreList":[]} \ No newline at end of file +{"version":3,"file":"downstream.js","names":["firstValueFrom","filter","mergeMap","newRxError","stackCheckpoints","appendToArray","createRevision","ensureNotFalsy","flatClone","getDefaultRevision","getHeightOfRevision","now","PROMISE_RESOLVE_VOID","getLastCheckpointDoc","setCheckpoint","stripAttachmentsDataFromMetaWriteRows","writeDocToDocState","getAssumedMasterState","getMetaWriteRow","startReplicationDownstream","state","input","initialCheckpoint","downstream","checkpointDoc","identifierHash","hashFunction","identifier","replicationHandler","timer","openTasks","addNewTask","task","stats","down","taskWithTime","time","push","streamQueue","then","useTasks","length","events","active","next","innerTaskWithTime","shift","lastTimeMasterChangesRequested","downstreamResyncOnce","downstreamProcessChanges","firstSyncDone","getValue","canceled","sub","masterChangeStream$","pipe","ev","up","s","subscribe","masterChangeStreamEmit","unsubscribe","checkpointQueue","lastCheckpoint","promises","downResult","masterChangesSince","pullBatchSize","documents","checkpoint","persistFromMaster","Promise","all","tasks","docsOfAllTasks","forEach","Error","persistenceQueue","nonPersistedFromMaster","docs","primaryPath","docData","docId","downDocsById","useCheckpoint","docIds","Object","keys","writeRowsToFork","writeRowsToForkById","writeRowsToMeta","useMetaWriteRows","forkInstance","findDocumentsById","currentForkStateList","assumedMasterState","currentForkState","Map","doc","set","map","forkStateFullDoc","get","forkStateDocData","hasAttachments","undefined","masterState","assumedMaster","metaDocument","isResolvedConflict","_rev","isAssumedMasterEqualToForkState","conflictHandler","realMasterState","newDocumentState","r","isEqual","_meta","o","hash","areStatesExactlyEqual","newForkState","assign","_attachments","lwt","nextRevisionHeight","keepMeta","forkWriteRow","previous","document","bulkWrite","downstreamBulkWriteFlag","forkWriteResult","success","processed","error","status","writeError","metaInstance","metaWriteResult","id","documentId","catch","unhandledError"],"sources":["../../../src/replication-protocol/downstream.ts"],"sourcesContent":["import {\n firstValueFrom,\n filter,\n mergeMap\n} from 'rxjs';\nimport { newRxError } from '../rx-error.ts';\nimport { stackCheckpoints } from '../rx-storage-helper.ts';\nimport type {\n RxStorageInstanceReplicationState,\n BulkWriteRow,\n BulkWriteRowById,\n RxStorageReplicationMeta,\n RxDocumentData,\n ById,\n WithDeleted,\n DocumentsWithCheckpoint,\n WithDeletedAndAttachments\n} from '../types/index.d.ts';\nimport {\n appendToArray,\n createRevision,\n ensureNotFalsy,\n flatClone,\n getDefaultRevision,\n getHeightOfRevision,\n now,\n PROMISE_RESOLVE_VOID\n} from '../plugins/utils/index.ts';\nimport {\n getLastCheckpointDoc,\n setCheckpoint\n} from './checkpoint.ts';\nimport {\n stripAttachmentsDataFromMetaWriteRows,\n writeDocToDocState\n} from './helper.ts';\nimport {\n getAssumedMasterState,\n getMetaWriteRow\n} from './meta-instance.ts';\n\n/**\n * Writes all documents from the master to the fork.\n * The downstream has two operation modes\n * - Sync by iterating over the checkpoints via downstreamResyncOnce()\n * - Sync by listening to the changestream via downstreamProcessChanges()\n * We need this to be able to do initial syncs\n * and still can have fast event based sync when the client is not offline.\n */\nexport async function startReplicationDownstream(\n state: RxStorageInstanceReplicationState\n) {\n if (\n state.input.initialCheckpoint &&\n state.input.initialCheckpoint.downstream\n ) {\n const checkpointDoc = await getLastCheckpointDoc(state, 'down');\n if (!checkpointDoc) {\n await setCheckpoint(\n state,\n 'down',\n state.input.initialCheckpoint.downstream\n );\n }\n }\n\n const identifierHash = await state.input.hashFunction(state.input.identifier);\n const replicationHandler = state.input.replicationHandler;\n\n // used to detect which tasks etc can in it at which order.\n let timer = 0;\n\n\n type Task = DocumentsWithCheckpoint | 'RESYNC';\n type TaskWithTime = {\n time: number;\n task: Task;\n };\n const openTasks: TaskWithTime[] = [];\n\n\n function addNewTask(task: Task): void {\n state.stats.down.addNewTask = state.stats.down.addNewTask + 1;\n const taskWithTime = {\n time: timer++,\n task\n };\n openTasks.push(taskWithTime);\n state.streamQueue.down = state.streamQueue.down\n .then(() => {\n const useTasks: Task[] = [];\n while (openTasks.length > 0) {\n state.events.active.down.next(true);\n const innerTaskWithTime = ensureNotFalsy(openTasks.shift());\n\n /**\n * If the task came in before the last time we started the pull\n * from the master, then we can drop the task.\n */\n if (innerTaskWithTime.time < lastTimeMasterChangesRequested) {\n continue;\n }\n\n if (innerTaskWithTime.task === 'RESYNC') {\n if (useTasks.length === 0) {\n useTasks.push(innerTaskWithTime.task);\n break;\n } else {\n break;\n }\n }\n\n useTasks.push(innerTaskWithTime.task);\n }\n if (useTasks.length === 0) {\n return;\n }\n\n if (useTasks[0] === 'RESYNC') {\n return downstreamResyncOnce();\n } else {\n return downstreamProcessChanges(useTasks);\n }\n }).then(() => {\n state.events.active.down.next(false);\n if (\n !state.firstSyncDone.down.getValue() &&\n !state.events.canceled.getValue()\n ) {\n state.firstSyncDone.down.next(true);\n }\n });\n }\n addNewTask('RESYNC');\n\n /**\n * If a write on the master happens, we have to trigger the downstream.\n * Only do this if not canceled yet, otherwise firstValueFrom errors\n * when running on a completed observable.\n */\n if (!state.events.canceled.getValue()) {\n const sub = replicationHandler\n .masterChangeStream$\n .pipe(\n mergeMap(async (ev) => {\n /**\n * While a push is running, we have to delay all incoming\n * events from the server to not mix up the replication state.\n */\n await firstValueFrom(\n state.events.active.up.pipe(filter(s => !s))\n );\n return ev;\n })\n )\n .subscribe((task: Task) => {\n state.stats.down.masterChangeStreamEmit = state.stats.down.masterChangeStreamEmit + 1;\n addNewTask(task);\n });\n firstValueFrom(\n state.events.canceled.pipe(\n filter(canceled => !!canceled)\n )\n ).then(() => sub.unsubscribe());\n }\n\n\n /**\n * For faster performance, we directly start each write\n * and then await all writes at the end.\n */\n let lastTimeMasterChangesRequested: number = -1;\n async function downstreamResyncOnce() {\n state.stats.down.downstreamResyncOnce = state.stats.down.downstreamResyncOnce + 1;\n if (state.events.canceled.getValue()) {\n return;\n }\n\n state.checkpointQueue = state.checkpointQueue.then(() => getLastCheckpointDoc(state, 'down'));\n let lastCheckpoint: CheckpointType = await state.checkpointQueue;\n\n\n const promises: Promise[] = [];\n while (!state.events.canceled.getValue()) {\n lastTimeMasterChangesRequested = timer++;\n const downResult = await replicationHandler.masterChangesSince(\n lastCheckpoint,\n state.input.pullBatchSize\n );\n\n if (downResult.documents.length === 0) {\n break;\n }\n\n lastCheckpoint = stackCheckpoints([lastCheckpoint, downResult.checkpoint]);\n\n promises.push(\n persistFromMaster(\n downResult.documents,\n lastCheckpoint\n )\n );\n\n /**\n * By definition we stop pull when the pulled documents\n * do not fill up the pullBatchSize because we\n * can assume that the remote has no more documents.\n */\n if (downResult.documents.length < state.input.pullBatchSize) {\n break;\n }\n\n }\n await Promise.all(promises);\n }\n\n\n function downstreamProcessChanges(tasks: Task[]) {\n state.stats.down.downstreamProcessChanges = state.stats.down.downstreamProcessChanges + 1;\n const docsOfAllTasks: WithDeleted[] = [];\n let lastCheckpoint: CheckpointType | undefined = null as any;\n\n tasks.forEach(task => {\n if (task === 'RESYNC') {\n throw new Error('SNH');\n }\n appendToArray(docsOfAllTasks, task.documents);\n lastCheckpoint = stackCheckpoints([lastCheckpoint, task.checkpoint]);\n });\n return persistFromMaster(\n docsOfAllTasks,\n ensureNotFalsy(lastCheckpoint)\n );\n }\n\n\n /**\n * It can happen that the calls to masterChangesSince() or the changeStream()\n * are way faster then how fast the documents can be persisted.\n * Therefore we merge all incoming downResults into the nonPersistedFromMaster object\n * and process them together if possible.\n * This often bundles up single writes and improves performance\n * by processing the documents in bulks.\n */\n let persistenceQueue = PROMISE_RESOLVE_VOID;\n const nonPersistedFromMaster: {\n checkpoint?: CheckpointType;\n docs: ById>;\n } = {\n docs: {}\n };\n\n function persistFromMaster(\n docs: WithDeleted[],\n checkpoint: CheckpointType\n ): Promise {\n const primaryPath = state.primaryPath;\n state.stats.down.persistFromMaster = state.stats.down.persistFromMaster + 1;\n\n /**\n * Add the new docs to the non-persistent list\n */\n docs.forEach(docData => {\n const docId: string = (docData as any)[primaryPath];\n nonPersistedFromMaster.docs[docId] = docData;\n });\n nonPersistedFromMaster.checkpoint = checkpoint;\n\n /**\n * Run in the queue\n * with all open documents from nonPersistedFromMaster.\n */\n persistenceQueue = persistenceQueue.then(() => {\n\n const downDocsById: ById> = nonPersistedFromMaster.docs;\n nonPersistedFromMaster.docs = {};\n const useCheckpoint = nonPersistedFromMaster.checkpoint;\n const docIds = Object.keys(downDocsById);\n\n if (\n state.events.canceled.getValue() ||\n docIds.length === 0\n ) {\n return PROMISE_RESOLVE_VOID;\n }\n\n const writeRowsToFork: BulkWriteRow[] = [];\n const writeRowsToForkById: ById> = {};\n const writeRowsToMeta: BulkWriteRowById> = {};\n const useMetaWriteRows: BulkWriteRow>[] = [];\n\n return Promise.all([\n state.input.forkInstance.findDocumentsById(docIds, true),\n getAssumedMasterState(\n state,\n docIds\n )\n ]).then(([\n currentForkStateList,\n assumedMasterState\n ]) => {\n const currentForkState = new Map>();\n currentForkStateList.forEach(doc => currentForkState.set((doc as any)[primaryPath], doc));\n return Promise.all(\n docIds.map(async (docId) => {\n const forkStateFullDoc: RxDocumentData | undefined = currentForkState.get(docId);\n const forkStateDocData: WithDeletedAndAttachments | undefined = forkStateFullDoc\n ? writeDocToDocState(forkStateFullDoc, state.hasAttachments, false)\n : undefined\n ;\n const masterState = downDocsById[docId];\n const assumedMaster = assumedMasterState[docId];\n\n if (\n assumedMaster &&\n forkStateFullDoc &&\n assumedMaster.metaDocument.isResolvedConflict === forkStateFullDoc._rev\n ) {\n /**\n * The current fork state represents a resolved conflict\n * that first must be send to the master in the upstream.\n * All conflicts are resolved by the upstream.\n */\n // return PROMISE_RESOLVE_VOID;\n await state.streamQueue.up;\n }\n\n let isAssumedMasterEqualToForkState = !assumedMaster || !forkStateDocData ?\n false :\n await state.input.conflictHandler({\n realMasterState: assumedMaster.docData,\n newDocumentState: forkStateDocData\n }, 'downstream-check-if-equal-0').then(r => r.isEqual);\n if (\n !isAssumedMasterEqualToForkState &&\n (\n assumedMaster &&\n (assumedMaster.docData as any)._rev &&\n forkStateFullDoc &&\n forkStateFullDoc._meta[state.input.identifier] &&\n getHeightOfRevision(forkStateFullDoc._rev) === forkStateFullDoc._meta[state.input.identifier]\n )\n ) {\n isAssumedMasterEqualToForkState = true;\n }\n if (\n (\n (\n forkStateFullDoc &&\n assumedMaster &&\n isAssumedMasterEqualToForkState === false\n ) ||\n (\n forkStateFullDoc && !assumedMaster\n )\n ) &&\n !(\n forkStateFullDoc._meta.o &&\n (\n forkStateFullDoc._meta.o.hash === identifierHash &&\n forkStateFullDoc._meta.o._rev === getHeightOfRevision(forkStateFullDoc._rev)\n )\n )\n ) {\n /**\n * We have a non-upstream-replicated\n * local write to the fork.\n * This means either we have to upstream the local\n * doc data first, or it means that the fork state was\n * synced from the master but the process exited before\n * the metadata was written.\n * @link https://github.com/pubkey/rxdb/pull/7804\n */\n return PROMISE_RESOLVE_VOID;\n }\n\n const areStatesExactlyEqual = !forkStateDocData\n ? false\n : await state.input.conflictHandler(\n {\n realMasterState: masterState,\n newDocumentState: forkStateDocData\n },\n 'downstream-check-if-equal-1'\n ).then(r => r.isEqual);\n if (\n forkStateDocData &&\n areStatesExactlyEqual\n ) {\n /**\n * Document states are exactly equal.\n * This can happen when the replication is shut down\n * unexpected like when the user goes offline.\n *\n * Only when the assumedMaster is different from the forkState,\n * we have to patch the document in the meta instance.\n */\n if (\n !assumedMaster ||\n isAssumedMasterEqualToForkState === false\n ) {\n useMetaWriteRows.push(\n await getMetaWriteRow(\n state,\n forkStateDocData,\n assumedMaster ? assumedMaster.metaDocument : undefined\n )\n );\n }\n return PROMISE_RESOLVE_VOID;\n }\n\n /**\n * All other master states need to be written to the forkInstance\n * and metaInstance.\n */\n const newForkState = Object.assign(\n {},\n masterState,\n forkStateFullDoc ? {\n _meta: flatClone(forkStateFullDoc._meta),\n _attachments: state.hasAttachments && masterState._attachments ? masterState._attachments : {},\n _rev: getDefaultRevision()\n } : {\n _meta: {\n lwt: now()\n },\n _rev: getDefaultRevision(),\n _attachments: state.hasAttachments && masterState._attachments ? masterState._attachments : {}\n }\n );\n /**\n * If the remote works with revisions,\n * we store the height of the next fork-state revision\n * inside of the documents meta data.\n * By doing so we can filter it out in the upstream\n * and detect the document as being equal to master or not.\n * This is used for example in the CouchDB replication plugin.\n */\n if ((masterState as any)._rev) {\n const nextRevisionHeight = !forkStateFullDoc ? 1 : getHeightOfRevision(forkStateFullDoc._rev) + 1;\n newForkState._meta[state.input.identifier] = nextRevisionHeight;\n if (state.input.keepMeta) {\n newForkState._rev = (masterState as any)._rev;\n }\n }\n if (\n state.input.keepMeta &&\n (masterState as any)._meta\n ) {\n newForkState._meta = (masterState as any)._meta;\n }\n\n /**\n * Tag the write with its origin so a later downstream run can tell\n * \"fork differs from assumed master\" caused by a local write apart\n * from one caused by a lost meta write. A local write bumps the\n * revision height and voids the marker.\n */\n newForkState._meta.o = {\n _rev: !forkStateFullDoc ? 1 : getHeightOfRevision(forkStateFullDoc._rev) + 1,\n hash: identifierHash\n };\n\n const forkWriteRow = {\n previous: forkStateFullDoc,\n document: newForkState\n };\n\n forkWriteRow.document._rev = forkWriteRow.document._rev ? forkWriteRow.document._rev : createRevision(\n identifierHash,\n forkWriteRow.previous\n );\n writeRowsToFork.push(forkWriteRow);\n writeRowsToForkById[docId] = forkWriteRow;\n writeRowsToMeta[docId] = await getMetaWriteRow(\n state,\n masterState,\n assumedMaster ? assumedMaster.metaDocument : undefined\n );\n })\n );\n }).then(async () => {\n if (writeRowsToFork.length > 0) {\n return state.input.forkInstance.bulkWrite(\n writeRowsToFork,\n await state.downstreamBulkWriteFlag\n ).then((forkWriteResult) => {\n forkWriteResult.success.forEach(doc => {\n const docId = (doc as any)[primaryPath];\n state.events.processed.down.next(writeRowsToForkById[docId]);\n useMetaWriteRows.push(writeRowsToMeta[docId]);\n });\n forkWriteResult.error.forEach(error => {\n /**\n * We do not have to care about downstream conflict errors here\n * because on conflict, it will be solved locally and result in another write.\n */\n if (error.status === 409) {\n return;\n }\n // other non-conflict errors must be handled\n state.events.error.next(newRxError('RC_PULL', {\n writeError: error\n }));\n });\n });\n }\n }).then(() => {\n if (useMetaWriteRows.length > 0) {\n return state.input.metaInstance.bulkWrite(\n stripAttachmentsDataFromMetaWriteRows(state, useMetaWriteRows),\n 'replication-down-write-meta'\n ).then(metaWriteResult => {\n metaWriteResult.error\n .forEach(writeError => {\n state.events.error.next(newRxError('RC_PULL', {\n id: writeError.documentId,\n writeError\n }));\n });\n });\n }\n }).then(() => {\n /**\n * For better performance we do not await checkpoint writes,\n * but to ensure order on parallel checkpoint writes,\n * we have to use a queue.\n */\n setCheckpoint(\n state,\n 'down',\n useCheckpoint\n );\n });\n }).catch(unhandledError => state.events.error.next(unhandledError));\n return persistenceQueue;\n }\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/esm/types/rx-document.d.js.map b/dist/esm/types/rx-document.d.js.map index eb6baf2addd..c5a9e8f8a60 100644 --- a/dist/esm/types/rx-document.d.js.map +++ b/dist/esm/types/rx-document.d.js.map @@ -1 +1 @@ -{"version":3,"file":"rx-document.d.js","names":[],"sources":["../../../src/types/rx-document.d.ts"],"sourcesContent":["import {\n Observable\n} from 'rxjs';\n\nimport type {\n RxCollection,\n} from './rx-collection.d.ts';\nimport type {\n RxAttachment,\n RxAttachmentCreator\n} from './rx-attachment.d.ts';\nimport type { RxDocumentData, WithDeleted } from './rx-storage.d.ts';\nimport type { RxChangeEvent } from './rx-change-event.d.ts';\nimport type { DeepReadonly, MaybePromise, PlainJsonValue } from './util.d.ts';\nimport type { UpdateQuery } from './plugins/update.d.ts';\nimport type { CRDTEntry } from './plugins/crdt.d.ts';\n\n\n\nexport type RxDocument = RxDocumentBase<\n RxDocumentType,\n OrmMethods,\n Reactivity\n> & RxDocumentType & OrmMethods & ExtendObservables & ExtendReactivity;\n\n\n/**\n * Extend the base properties by the property$ fields\n * so it knows that RxDocument.age also has RxDocument.age$ which is\n * an observable.\n * TODO how to do this for the nested fields?\n */\ntype ExtendObservables = {\n [P in keyof RxDocumentType as `${string & P}$`]: Observable;\n};\n\ntype ExtendReactivity = {\n [P in keyof RxDocumentType as `${string & P}$$`]: Reactivity;\n};\n\n/**\n * The public facing modify update function.\n * It only gets the document parts as input, that\n * are mutateable by the user.\n */\nexport type ModifyFunction = (\n doc: WithDeleted\n) => MaybePromise> | MaybePromise;\n\n/**\n * Meta data that is attached to each document by RxDB.\n */\nexport type RxDocumentMeta = {\n /**\n * Last write time.\n * Unix epoch in milliseconds.\n */\n lwt: number;\n\n /**\n * Any other value can be attached to the _meta data.\n * Mostly done by plugins to mark documents.\n */\n [k: string]: PlainJsonValue;\n};\n\nexport declare interface RxDocumentBase {\n isInstanceOfRxDocument: true;\n collection: RxCollection;\n readonly deleted: boolean;\n\n readonly $: Observable>;\n readonly $$: Reactivity;\n readonly deleted$: Observable;\n readonly deleted$$: Reactivity;\n\n readonly primary: string;\n readonly allAttachments$: Observable[]>;\n\n // internal things\n _data: RxDocumentData;\n primaryPath: string;\n revision: string;\n /**\n * Used to de-duplicate the enriched property objects\n * of the document.\n */\n _propertyCache: Map;\n $emit(cE: RxChangeEvent): void;\n _saveData(newData: any, oldData: any): Promise>;\n // /internal things\n\n // Returns the latest state of the document\n getLatest(): RxDocument;\n\n\n get$(path: string): Observable;\n get$$(path: string): Reactivity;\n get(objPath: string): DeepReadonly;\n populate(objPath: string): Promise | any | null>;\n\n /**\n * mutate the document with a function\n */\n modify(mutationFunction: ModifyFunction, context?: string): Promise>;\n incrementalModify(mutationFunction: ModifyFunction, context?: string): Promise>;\n\n /**\n * patches the given properties\n */\n patch(patch: Partial): Promise>;\n incrementalPatch(patch: Partial): Promise>;\n\n update(updateObj: UpdateQuery): Promise>;\n incrementalUpdate(updateObj: UpdateQuery): Promise>;\n\n updateCRDT(updateObj: CRDTEntry | CRDTEntry[]): Promise>;\n\n remove(): Promise>;\n incrementalRemove(): Promise>;\n\n // only for temporary documents\n set(objPath: string, value: any): RxDocument;\n save(): Promise;\n\n // attachments\n putAttachment(\n creator: RxAttachmentCreator\n ): Promise>;\n getAttachment(id: string): RxAttachment | null;\n allAttachments(): RxAttachment[];\n\n toJSON(withRevAndAttachments: true): DeepReadonly>;\n toJSON(withRevAndAttachments?: false): DeepReadonly;\n\n toMutableJSON(withRevAndAttachments: true): RxDocumentData;\n toMutableJSON(withRevAndAttachments?: false): RxDocType;\n\n destroy(): void;\n}\n"],"mappings":"","ignoreList":[]} \ No newline at end of file +{"version":3,"file":"rx-document.d.js","names":[],"sources":["../../../src/types/rx-document.d.ts"],"sourcesContent":["import {\n Observable\n} from 'rxjs';\n\nimport type {\n RxCollection,\n} from './rx-collection.d.ts';\nimport type {\n RxAttachment,\n RxAttachmentCreator\n} from './rx-attachment.d.ts';\nimport type { RxDocumentData, WithDeleted } from './rx-storage.d.ts';\nimport type { RxChangeEvent } from './rx-change-event.d.ts';\nimport type { DeepReadonly, MaybePromise, PlainJsonValue } from './util.d.ts';\nimport type { UpdateQuery } from './plugins/update.d.ts';\nimport type { CRDTEntry } from './plugins/crdt.d.ts';\n\n\n\nexport type RxDocument = RxDocumentBase<\n RxDocumentType,\n OrmMethods,\n Reactivity\n> & RxDocumentType & OrmMethods & ExtendObservables & ExtendReactivity;\n\n\n/**\n * Extend the base properties by the property$ fields\n * so it knows that RxDocument.age also has RxDocument.age$ which is\n * an observable.\n * TODO how to do this for the nested fields?\n */\ntype ExtendObservables = {\n [P in keyof RxDocumentType as `${string & P}$`]: Observable;\n};\n\ntype ExtendReactivity = {\n [P in keyof RxDocumentType as `${string & P}$$`]: Reactivity;\n};\n\n/**\n * The public facing modify update function.\n * It only gets the document parts as input, that\n * are mutateable by the user.\n */\nexport type ModifyFunction = (\n doc: WithDeleted\n) => MaybePromise> | MaybePromise;\n\n/**\n * Meta data that is attached to each document by RxDB.\n */\nexport type RxDocumentMeta = {\n /**\n * Last write time.\n * Unix epoch in milliseconds.\n */\n lwt: number;\n\n /**\n * The replication plugins \"tags\" the origin\n * of writes to later know if a write came from\n * the replication or was done locally.\n */\n o?: {\n hash: string;\n _rev: number;\n };\n\n /**\n * Any other value can be attached to the _meta data.\n * Mostly done by plugins to mark documents.\n */\n [k: string]: PlainJsonValue | undefined;\n};\n\nexport declare interface RxDocumentBase {\n isInstanceOfRxDocument: true;\n collection: RxCollection;\n readonly deleted: boolean;\n\n readonly $: Observable>;\n readonly $$: Reactivity;\n readonly deleted$: Observable;\n readonly deleted$$: Reactivity;\n\n readonly primary: string;\n readonly allAttachments$: Observable[]>;\n\n // internal things\n _data: RxDocumentData;\n primaryPath: string;\n revision: string;\n /**\n * Used to de-duplicate the enriched property objects\n * of the document.\n */\n _propertyCache: Map;\n $emit(cE: RxChangeEvent): void;\n _saveData(newData: any, oldData: any): Promise>;\n // /internal things\n\n // Returns the latest state of the document\n getLatest(): RxDocument;\n\n\n get$(path: string): Observable;\n get$$(path: string): Reactivity;\n get(objPath: string): DeepReadonly;\n populate(objPath: string): Promise | any | null>;\n\n /**\n * mutate the document with a function\n */\n modify(mutationFunction: ModifyFunction, context?: string): Promise>;\n incrementalModify(mutationFunction: ModifyFunction, context?: string): Promise>;\n\n /**\n * patches the given properties\n */\n patch(patch: Partial): Promise>;\n incrementalPatch(patch: Partial): Promise>;\n\n update(updateObj: UpdateQuery): Promise>;\n incrementalUpdate(updateObj: UpdateQuery): Promise>;\n\n updateCRDT(updateObj: CRDTEntry | CRDTEntry[]): Promise>;\n\n remove(): Promise>;\n incrementalRemove(): Promise>;\n\n // only for temporary documents\n set(objPath: string, value: any): RxDocument;\n save(): Promise;\n\n // attachments\n putAttachment(\n creator: RxAttachmentCreator\n ): Promise>;\n getAttachment(id: string): RxAttachment | null;\n allAttachments(): RxAttachment[];\n\n toJSON(withRevAndAttachments: true): DeepReadonly>;\n toJSON(withRevAndAttachments?: false): DeepReadonly;\n\n toMutableJSON(withRevAndAttachments: true): RxDocumentData;\n toMutableJSON(withRevAndAttachments?: false): RxDocType;\n\n destroy(): void;\n}\n"],"mappings":"","ignoreList":[]} \ No newline at end of file diff --git a/dist/esm/types/util.d.js.map b/dist/esm/types/util.d.js.map index 9d1b26e0974..08295e33e92 100644 --- a/dist/esm/types/util.d.js.map +++ b/dist/esm/types/util.d.js.map @@ -1 +1 @@ -{"version":3,"file":"util.d.js","names":[],"sources":["../../../src/types/util.d.ts"],"sourcesContent":["import type { RxStorage } from './rx-storage.interface';\n\nexport type MaybePromise = Promise | T;\n\n\nexport type PlainJsonValue = string | number | boolean | PlainSimpleJsonObject | PlainSimpleJsonObject[] | PlainJsonValue[];\nexport type PlainSimpleJsonObject = {\n [k: string]: PlainJsonValue | PlainJsonValue[];\n};\n\n/**\n * @link https://stackoverflow.com/a/49670389/3443137\n */\ntype DeepReadonly =\n T extends (infer R)[] ? DeepReadonlyArray :\n T extends Function ? T :\n T extends object ? DeepReadonlyObject :\n T;\n\ninterface DeepReadonlyArray extends ReadonlyArray> { }\n\ntype DeepReadonlyObject = {\n readonly [P in keyof T]: DeepReadonly;\n};\n\nexport type MaybeReadonly = T | Readonly;\n\n\n/**\n * Opposite of DeepReadonly,\n * makes everything mutable again.\n */\ntype DeepMutable = (\n T extends object\n ? {\n -readonly [K in keyof T]: (\n T[K] extends object\n ? DeepMutable\n : T[K]\n )\n }\n : never\n);\n\n/**\n * Can be used like 'keyof'\n * but only represents the string keys, not the Symbols or numbers.\n * @link https://stackoverflow.com/a/51808262/3443137\n */\nexport type StringKeys = Extract;\n\nexport type AnyKeys = { [P in keyof T]?: T[P] | any };\nexport interface AnyObject {\n [k: string]: any;\n}\n\n/**\n * @link https://dev.to/vborodulin/ts-how-to-override-properties-with-type-intersection-554l\n */\nexport type Override = Omit & T2;\n\n\n\nexport type ById = {\n [id: string]: T;\n};\n\n/**\n * Must be async to support async hashing like from the WebCrypto API.\n */\nexport type HashFunction = (input: string) => Promise;\n\nexport declare type QueryMatcher = (doc: DocType | DeepReadonly) => boolean;\n\n/**\n * To have a deterministic sorting, we cannot return 0,\n * we only return 1 or -1.\n * This ensures that we always end with the same output array, no mather of the\n * pre-sorting of the input array.\n */\nexport declare type DeterministicSortComparator = (a: DocType, b: DocType) => 1 | -1;\n\n/**\n * To test a storage, we need these\n * configuration values.\n */\nexport type RxTestStorage = {\n // can be used to setup async stuff\n readonly init?: () => any;\n // TODO remove name here, it can be read out already via getStorage().name\n readonly name: string;\n readonly getStorage: () => RxStorage;\n /**\n * Returns a storage that is used in performance tests.\n * For example in a browser it should return the storage with an IndexedDB based adapter,\n * while in node.js it must use the filesystem.\n */\n readonly getPerformanceStorage: () => {\n storage: RxStorage;\n /**\n * A description that describes the storage and setting.\n * For example 'dexie-native'.\n */\n description: string;\n };\n /**\n * True if the storage is able to\n * keep data after an instance is closed and opened again.\n */\n readonly hasPersistence: boolean;\n readonly hasMultiInstance: boolean;\n readonly hasAttachments: boolean;\n\n /**\n * Some storages likes the memory-synced storage,\n * are not able to provide a replication while guaranteeing\n * data integrity.\n */\n readonly hasReplication: boolean;\n\n /**\n * To make it possible to test alternative encryption plugins,\n * you can specify hasEncryption to signal\n * the test runner that the given storage already contains an\n * encryption plugin that should be used to test encryption tests.\n * Otherwise the encryption-crypto-js plugin will be tested.\n *\n * hasEncryption must contain a function that is able\n * to create a new password.\n */\n readonly hasEncryption?: () => Promise;\n};\n\n\n/**\n * The paths as strings-type of nested object\n * @link https://stackoverflow.com/a/58436959/3443137\n */\ntype Join = K extends string | number ?\n P extends string | number ?\n `${K}${'' extends P ? '' : '.'}${P}`\n : never : never;\n\nexport type Paths = [D] extends [never] ? never : T extends object ?\n { [K in keyof T]-?: K extends string | number ?\n `${K}` | (Paths extends infer R ? Join : never)\n : never\n }[keyof T] : '';\n\nexport type Leaves = [D] extends [never] ? never : T extends object ?\n { [K in keyof T]-?: Join> }[keyof T] : '';\ntype Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\n 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...0[]];\n"],"mappings":"","ignoreList":[]} \ No newline at end of file +{"version":3,"file":"util.d.js","names":[],"sources":["../../../src/types/util.d.ts"],"sourcesContent":["import type { RxStorage } from './rx-storage.interface';\n\nexport type MaybePromise = Promise | T;\n\n\nexport type PlainJsonValue =\n string |\n number |\n boolean |\n PlainSimpleJsonObject |\n PlainSimpleJsonObject[] |\n PlainJsonValue[] |\n { [key: string]: PlainJsonValue; };\nexport type PlainSimpleJsonObject = {\n [k: string]: PlainJsonValue | PlainJsonValue[];\n};\n\n/**\n * @link https://stackoverflow.com/a/49670389/3443137\n */\ntype DeepReadonly =\n T extends (infer R)[] ? DeepReadonlyArray :\n T extends Function ? T :\n T extends object ? DeepReadonlyObject :\n T;\n\ninterface DeepReadonlyArray extends ReadonlyArray> { }\n\ntype DeepReadonlyObject = {\n readonly [P in keyof T]: DeepReadonly;\n};\n\nexport type MaybeReadonly = T | Readonly;\n\n\n/**\n * Opposite of DeepReadonly,\n * makes everything mutable again.\n */\ntype DeepMutable = (\n T extends object\n ? {\n -readonly [K in keyof T]: (\n T[K] extends object\n ? DeepMutable\n : T[K]\n )\n }\n : never\n);\n\n/**\n * Can be used like 'keyof'\n * but only represents the string keys, not the Symbols or numbers.\n * @link https://stackoverflow.com/a/51808262/3443137\n */\nexport type StringKeys = Extract;\n\nexport type AnyKeys = { [P in keyof T]?: T[P] | any };\nexport interface AnyObject {\n [k: string]: any;\n}\n\n/**\n * @link https://dev.to/vborodulin/ts-how-to-override-properties-with-type-intersection-554l\n */\nexport type Override = Omit & T2;\n\n\n\nexport type ById = {\n [id: string]: T;\n};\n\n/**\n * Must be async to support async hashing like from the WebCrypto API.\n */\nexport type HashFunction = (input: string) => Promise;\n\nexport declare type QueryMatcher = (doc: DocType | DeepReadonly) => boolean;\n\n/**\n * To have a deterministic sorting, we cannot return 0,\n * we only return 1 or -1.\n * This ensures that we always end with the same output array, no mather of the\n * pre-sorting of the input array.\n */\nexport declare type DeterministicSortComparator = (a: DocType, b: DocType) => 1 | -1;\n\n/**\n * To test a storage, we need these\n * configuration values.\n */\nexport type RxTestStorage = {\n // can be used to setup async stuff\n readonly init?: () => any;\n // TODO remove name here, it can be read out already via getStorage().name\n readonly name: string;\n readonly getStorage: () => RxStorage;\n /**\n * Returns a storage that is used in performance tests.\n * For example in a browser it should return the storage with an IndexedDB based adapter,\n * while in node.js it must use the filesystem.\n */\n readonly getPerformanceStorage: () => {\n storage: RxStorage;\n /**\n * A description that describes the storage and setting.\n * For example 'dexie-native'.\n */\n description: string;\n };\n /**\n * True if the storage is able to\n * keep data after an instance is closed and opened again.\n */\n readonly hasPersistence: boolean;\n readonly hasMultiInstance: boolean;\n readonly hasAttachments: boolean;\n\n /**\n * Some storages likes the memory-synced storage,\n * are not able to provide a replication while guaranteeing\n * data integrity.\n */\n readonly hasReplication: boolean;\n\n /**\n * To make it possible to test alternative encryption plugins,\n * you can specify hasEncryption to signal\n * the test runner that the given storage already contains an\n * encryption plugin that should be used to test encryption tests.\n * Otherwise the encryption-crypto-js plugin will be tested.\n *\n * hasEncryption must contain a function that is able\n * to create a new password.\n */\n readonly hasEncryption?: () => Promise;\n};\n\n\n/**\n * The paths as strings-type of nested object\n * @link https://stackoverflow.com/a/58436959/3443137\n */\ntype Join = K extends string | number ?\n P extends string | number ?\n `${K}${'' extends P ? '' : '.'}${P}`\n : never : never;\n\nexport type Paths = [D] extends [never] ? never : T extends object ?\n { [K in keyof T]-?: K extends string | number ?\n `${K}` | (Paths extends infer R ? Join : never)\n : never\n }[keyof T] : '';\n\nexport type Leaves = [D] extends [never] ? never : T extends object ?\n { [K in keyof T]-?: Join> }[keyof T] : '';\ntype Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10,\n 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, ...0[]];\n"],"mappings":"","ignoreList":[]} \ No newline at end of file diff --git a/dist/types/types/rx-document.d.ts b/dist/types/types/rx-document.d.ts index 4e9861a8ba9..f9baffc144c 100644 --- a/dist/types/types/rx-document.d.ts +++ b/dist/types/types/rx-document.d.ts @@ -57,11 +57,21 @@ export type RxDocumentMeta = { */ lwt: number; + /** + * The replication plugins "tags" the origin + * of writes to later know if a write came from + * the replication or was done locally. + */ + o?: { + hash: string; + _rev: number; + }; + /** * Any other value can be attached to the _meta data. * Mostly done by plugins to mark documents. */ - [k: string]: PlainJsonValue; + [k: string]: PlainJsonValue | undefined; }; export declare interface RxDocumentBase { diff --git a/dist/types/types/util.d.ts b/dist/types/types/util.d.ts index 2a9dbdbb495..b00f88e5c5e 100644 --- a/dist/types/types/util.d.ts +++ b/dist/types/types/util.d.ts @@ -3,7 +3,14 @@ import type { RxStorage } from './rx-storage.interface'; export type MaybePromise = Promise | T; -export type PlainJsonValue = string | number | boolean | PlainSimpleJsonObject | PlainSimpleJsonObject[] | PlainJsonValue[]; +export type PlainJsonValue = + string | + number | + boolean | + PlainSimpleJsonObject | + PlainSimpleJsonObject[] | + PlainJsonValue[] | + { [key: string]: PlainJsonValue; }; export type PlainSimpleJsonObject = { [k: string]: PlainJsonValue | PlainJsonValue[]; }; diff --git a/src/replication-protocol/downstream.ts b/src/replication-protocol/downstream.ts index 715aac70f01..81f5e76a9a4 100644 --- a/src/replication-protocol/downstream.ts +++ b/src/replication-protocol/downstream.ts @@ -345,19 +345,31 @@ export async function startReplicationDownstream { diff --git a/src/types/util.d.ts b/src/types/util.d.ts index 2a9dbdbb495..b00f88e5c5e 100644 --- a/src/types/util.d.ts +++ b/src/types/util.d.ts @@ -3,7 +3,14 @@ import type { RxStorage } from './rx-storage.interface'; export type MaybePromise = Promise | T; -export type PlainJsonValue = string | number | boolean | PlainSimpleJsonObject | PlainSimpleJsonObject[] | PlainJsonValue[]; +export type PlainJsonValue = + string | + number | + boolean | + PlainSimpleJsonObject | + PlainSimpleJsonObject[] | + PlainJsonValue[] | + { [key: string]: PlainJsonValue; }; export type PlainSimpleJsonObject = { [k: string]: PlainJsonValue | PlainJsonValue[]; }; diff --git a/test/unit/replication.test.ts b/test/unit/replication.test.ts index c1b23e39124..8836cc6f5bb 100644 --- a/test/unit/replication.test.ts +++ b/test/unit/replication.test.ts @@ -935,6 +935,166 @@ describe('replication.test.ts', () => { }); }); describeParallel('issues', () => { + /** + * @link https://github.com/pubkey/rxdb/pull/7804 + */ + function setupDownstreamTestReplication( + local: RxCollection, + remote: RxCollection + ) { + return replicateRxCollection({ + collection: local, + replicationIdentifier: 'downstream-test', + live: true, + pull: { + handler: getPullHandler(remote), + stream$: getPullStream(remote) + }, + push: { + handler: getPushHandler(remote) + } + }); + } + + /** + * Simulates a crash between fork write and meta write in downstream. + * + * When the process dies after forkInstance.bulkWrite() succeeds but before + * metaInstance.bulkWrite() completes, the fork has the new state but the + * assumed master in meta is stale. On the next downstream cycle, this + * mismatch is detected as a "non-upstream-replicated local write" and the + * document is skipped - expecting upstream to resolve the conflict. But + * upstream never picks it up because the fork write came from downstream, + * leaving the document permanently stuck. + */ + it('#7804 (1/2) should recover downstream sync after meta write is lost between fork and meta write (simulated crash)', async () => { + const { localCollection, remoteCollection } = await getTestCollections({ local: 0, remote: 0 }); + const docId = 'crash-test-doc'; + + // Insert initial document on remote + await remoteCollection.insert(schemaObjects.humanWithTimestampData({ + id: docId, + name: 'Initial', + age: 1 + })); + + // Start replication and let it sync the initial document + const replicationState = setupDownstreamTestReplication(localCollection, remoteCollection); + ensureReplicationHasNoErrors(replicationState); + await replicationState.awaitInitialReplication(); + + // Verify initial sync + const initialLocal = await localCollection.findOne(docId).exec(true); + assert.strictEqual(initialLocal.name, 'Initial'); + + // Monkey-patch metaInstance.bulkWrite to silently drop the next + // downstream meta write - simulating a crash between fork and meta write. + const metaInstance = ensureNotFalsy(replicationState.internalReplicationState).input.metaInstance; + const originalBulkWrite = metaInstance.bulkWrite.bind(metaInstance); + let metaWriteDropped = false; + + metaInstance.bulkWrite = function (rows: any[], context: string) { + if (context === 'replication-down-write-meta' && !metaWriteDropped) { + metaWriteDropped = true; + // Silently swallow the write: fork already persisted, meta is lost. + return Promise.resolve({ success: [], error: [] }); + } + return originalBulkWrite(rows, context); + } as any; + + // Update the document on remote. + // Downstream will write the new state to the fork, but the + // corresponding meta write is silently dropped above. + const remoteDoc = await remoteCollection.findOne(docId).exec(true); + const internalState = ensureNotFalsy(replicationState.internalReplicationState); + let prevDown = internalState.streamQueue.down; + await remoteDoc.incrementalPatch({ + name: 'FirstUpdate', + age: 2 + }); + + // Wait for the downstream cycle to finish + await waitUntil(() => internalState.streamQueue.down !== prevDown, undefined, 40); + await internalState.streamQueue.down; + + assert.ok(metaWriteDropped, 'Meta write should have been intercepted and dropped'); + const afterFirst = await localCollection.findOne(docId).exec(true); + assert.strictEqual(afterFirst.name, 'FirstUpdate'); + + // Restore original bulkWrite so meta works normally again. + metaInstance.bulkWrite = originalBulkWrite; + + // At this point the replication state is: + // forkState = { name: 'FirstUpdate', age: 2 } + // assumedMaster = { name: 'Initial', age: 1 } (stale - meta write was lost) + // + // Without the origin marker, downstream sees forkState != assumedMaster + // and treats it as a "non-upstream-replicated local write", skipping the document. + + // Update the document on remote again. + prevDown = internalState.streamQueue.down; + const remoteDoc2 = await remoteCollection.findOne(docId).exec(true); + await remoteDoc2.incrementalPatch({ + name: 'SecondUpdate', + age: 3 + }); + + // Wait for downstream to finish processing, then verify it recovered. + await waitUntil(() => internalState.streamQueue.down !== prevDown, undefined, 40); + await internalState.streamQueue.down; + + const localDoc = await localCollection.findOne(docId).exec(true); + assert.strictEqual(localDoc.name, 'SecondUpdate', 'should have replicated the second update from the remote'); + assert.strictEqual(localDoc.age, 3); + + await replicationState.cancel(); + await localCollection.database.destroy(); + await remoteCollection.database.destroy(); + }); + it('#7804 (2/2) should sync downstream updates when local and remote have different documents', async () => { + const { localCollection, remoteCollection } = await getTestCollections({ local: 0, remote: 0 }); + const docId = 'different-doc'; + + // Insert different documents in each + await remoteCollection.insert(schemaObjects.humanWithTimestampData({ + id: docId, + name: 'RemoteDocument', + age: 10 + })); + await localCollection.insert(schemaObjects.humanWithTimestampData({ + id: docId, + name: 'LocalDocument', + age: 20 + })); + + const replicationState = setupDownstreamTestReplication(localCollection, remoteCollection); + ensureReplicationHasNoErrors(replicationState); + + await replicationState.awaitInitialReplication(); + await replicationState.awaitInSync(); + + // Update document on remote + const internalState = ensureNotFalsy(replicationState.internalReplicationState); + const prevDown = internalState.streamQueue.down; + const remoteDoc = await remoteCollection.findOne(docId).exec(true); + await remoteDoc.incrementalPatch({ + name: 'UpdatedFromRemote', + age: 999 + }); + + // Wait for downstream cycle to complete + await waitUntil(() => internalState.streamQueue.down !== prevDown, 1000, 10); + await internalState.streamQueue.down; + + // Verify local received the update + const localDoc = await localCollection.findOne(docId).exec(true); + assert.strictEqual(localDoc.name, 'UpdatedFromRemote'); + assert.strictEqual(localDoc.age, 999); + + await replicationState.cancel(); + await localCollection.database.destroy(); + await remoteCollection.database.destroy(); + }); it('#4190 Composite Primary Keys broken on replicated collections', async () => { const db = await createRxDatabase({ name: randomCouchString(10),