a tool for shared writing and social publishing

add caching to flush operation

+60 -11
+60 -11
src/replicache/cachedServerMutationContext.ts
··· 168 168 return ctx; 169 169 }; 170 170 let flush = async () => { 171 + let flushStart = performance.now(); 172 + let timeInsertingEntities = 0; 173 + let timeProcessingFactWrites = 0; 174 + let timeTextMerging = 0; 175 + let timeFactInserts = 0; 176 + let timeDeletingEntities = 0; 177 + let timeDeletingFacts = 0; 178 + let timeCacheCleanup = 0; 179 + 180 + // Insert entities 181 + let entityInsertStart = performance.now(); 171 182 if (entitiesCache.length > 0) 172 183 await tx 173 184 .insert(entities) 174 185 .values(entitiesCache.map((e) => ({ set: e.set, id: e.id }))); 186 + timeInsertingEntities = performance.now() - entityInsertStart; 187 + 188 + // Process fact writes 189 + let factWritesStart = performance.now(); 175 190 let factWrites = writeCache.flatMap((f) => 176 191 f.type === "del" ? [] : [f.fact], 177 192 ); ··· 179 194 for (let f of factWrites) { 180 195 let attribute = Attributes[f.attribute as Attribute]; 181 196 let data = f.data; 197 + 198 + // Text merging timing 199 + let textMergeStart = performance.now(); 182 200 if (attribute.type === "text" && attribute.cardinality === "one") { 183 201 let values = Object.values( 184 202 textAttributeWriteCache[`${f.entity}-${f.attribute}`] || {}, 185 203 ); 186 204 if (values.length > 0) { 187 205 let existingFact = await scanIndex.eav(f.entity, f.attribute); 188 - if (existingFact[0]) values.push(existingFact[0].data.value); 189 - let updateBytes = Y.mergeUpdatesV1( 190 - values.map((v) => base64.toByteArray(v)), 191 - ); 192 - data.value = base64.fromByteArray(updateBytes); 206 + if (existingFact[0] && !values.includes(existingFact[0].data.value)) 207 + values.push(existingFact[0].data.value); 208 + if (values.length > 1) 209 + data.value = base64.fromByteArray( 210 + Y.mergeUpdatesV1(values.map((v) => base64.toByteArray(v))), 211 + ); 193 212 } 194 213 } 214 + timeTextMerging += performance.now() - textMergeStart; 195 215 196 - try { 197 - await tx 216 + // Fact insert timing 217 + let factInsertStart = performance.now(); 218 + await tx.transaction((tx2) => 219 + tx2 198 220 .insert(facts) 199 221 .values({ 200 222 id: f.id, ··· 205 227 .onConflictDoUpdate({ 206 228 target: facts.id, 207 229 set: { data: driz.sql`excluded.data` }, 208 - }); 209 - } catch (e) { 210 - console.log(`error on inserting fact: `, JSON.stringify(e)); 211 - } 230 + }) 231 + .catch((e) => 232 + console.log(`error on inserting fact: `, JSON.stringify(e)), 233 + ), 234 + ); 235 + timeFactInserts += performance.now() - factInsertStart; 212 236 } 213 237 } 238 + timeProcessingFactWrites = performance.now() - factWritesStart; 239 + 240 + // Delete entities 241 + let entityDeleteStart = performance.now(); 214 242 if (deleteEntitiesCache.length > 0) 215 243 await tx 216 244 .delete(entities) 217 245 .where(driz.inArray(entities.id, deleteEntitiesCache)); 246 + timeDeletingEntities = performance.now() - entityDeleteStart; 247 + 248 + // Delete facts 249 + let factDeleteStart = performance.now(); 218 250 let factDeletes = writeCache.flatMap((f) => 219 251 f.type === "put" ? [] : [f.fact.id], 220 252 ); ··· 235 267 await tx.delete(facts).where(driz.or(...conditions)); 236 268 } 237 269 } 270 + timeDeletingFacts = performance.now() - factDeleteStart; 238 271 272 + // Cache cleanup 273 + let cacheCleanupStart = performance.now(); 239 274 writeCache = []; 240 275 eavCache.clear(); 241 276 permissionsCache = {}; 242 277 entitiesCache = []; 243 278 permissionsCache = {}; 244 279 deleteEntitiesCache = []; 280 + timeCacheCleanup = performance.now() - cacheCleanupStart; 281 + 282 + let totalFlushTime = performance.now() - flushStart; 283 + console.log(` 284 + Flush Performance Breakdown (${totalFlushTime.toFixed(2)}ms): 285 + ========================================== 286 + Entity Insertions (${entitiesCache.length} entities): ${timeInsertingEntities.toFixed(2)}ms 287 + Fact Processing (${factWrites.length} facts): ${timeProcessingFactWrites.toFixed(2)}ms 288 + - Text Merging: ${timeTextMerging.toFixed(2)}ms 289 + - Fact Inserts (nested transactions): ${timeFactInserts.toFixed(2)}ms 290 + Entity Deletions (${deleteEntitiesCache.length} entities): ${timeDeletingEntities.toFixed(2)}ms 291 + Fact Deletions: ${timeDeletingFacts.toFixed(2)}ms 292 + Cache Cleanup: ${timeCacheCleanup.toFixed(2)}ms 293 + `); 245 294 }; 246 295 247 296 return {