|
11 | 11 | */ |
12 | 12 |
|
13 | 13 | import { parquetWriteBuffer } from '@dotdo/hyparquet-writer' |
14 | | -import { DeltaTable, type StorageBackend } from '@dotdo/deltalake' |
15 | 14 | import { ulid } from '../core/src/ulid' |
16 | | -import { sanitizeR2Path, buildSafeR2Path, sanitizePathSegment, InvalidR2PathError } from './utils' |
17 | | -import { createR2Storage } from '../core/src/deltalake-storage' |
18 | | -import { createEventsTable, getEventsTablePath, type EventDeltaRecord } from '../core/src/deltalake-factory' |
| 15 | +import { sanitizeR2Path } from './utils' |
19 | 16 |
|
20 | 17 | export { ulid } |
21 | 18 |
|
@@ -159,155 +156,6 @@ export async function writeEvents( |
159 | 156 | return { key, events: events.length, bytes: buffer.byteLength, cpuMs } |
160 | 157 | } |
161 | 158 |
|
162 | | -// ============================================================================ |
163 | | -// DeltaLake Event Writer |
164 | | -// ============================================================================ |
165 | | - |
166 | | -/** |
167 | | - * Result from a DeltaLake write operation. |
168 | | - */ |
169 | | -export interface DeltaWriteResult { |
170 | | - version: number |
171 | | - events: number |
172 | | - bytes: number |
173 | | - path: string |
174 | | - cpuMs: number |
175 | | -} |
176 | | - |
177 | | -/** |
178 | | - * Convert EventRecord to DeltaLake format (EventDeltaRecord). |
179 | | - */ |
180 | | -function toEventDeltaRecord(event: EventRecord): EventDeltaRecord { |
181 | | - return { |
182 | | - ts: event.ts, |
183 | | - type: event.type, |
184 | | - source: event.source ?? null, |
185 | | - provider: event.provider ?? null, |
186 | | - eventType: event.eventType ?? null, |
187 | | - verified: event.verified ?? null, |
188 | | - scriptName: event.scriptName ?? null, |
189 | | - outcome: event.outcome ?? null, |
190 | | - method: event.method ?? null, |
191 | | - url: event.url ?? null, |
192 | | - statusCode: event.statusCode ?? null, |
193 | | - durationMs: event.durationMs ?? null, |
194 | | - payload: event.payload ? JSON.stringify(event.payload) : null, |
195 | | - } |
196 | | -} |
197 | | - |
198 | | -/** |
199 | | - * DeltaLake table cache - one table per shard. |
200 | | - * Maps shardId to DeltaTable instance. |
201 | | - */ |
202 | | -const deltaTableCache = new Map<string, DeltaTable<EventDeltaRecord>>() |
203 | | - |
204 | | -/** |
205 | | - * Get or create a DeltaTable for a shard. |
206 | | - */ |
207 | | -function getDeltaTable( |
208 | | - storage: StorageBackend, |
209 | | - shardId: number |
210 | | -): DeltaTable<EventDeltaRecord> { |
211 | | - const cacheKey = `events-shard-${shardId}` |
212 | | - let table = deltaTableCache.get(cacheKey) |
213 | | - |
214 | | - if (!table) { |
215 | | - table = createEventsTable(storage, { shardId }) |
216 | | - deltaTableCache.set(cacheKey, table) |
217 | | - } |
218 | | - |
219 | | - return table |
220 | | -} |
221 | | - |
222 | | -/** |
223 | | - * Write events to R2 using DeltaLake for ACID guarantees. |
224 | | - * |
225 | | - * Events are written to a partitioned DeltaTable with transaction log support. |
226 | | - * Path structure: events/shard={shardId}/_delta_log/... |
227 | | - * |
228 | | - * @param bucket - R2 bucket for storage |
229 | | - * @param events - Events to write |
230 | | - * @param shardId - Shard ID for partitioning (default: 0) |
231 | | - * @returns Result with commit version and event count |
232 | | - * |
233 | | - * @example |
234 | | - * ```typescript |
235 | | - * const result = await writeEventsDelta(env.EVENTS_BUCKET, events, 2) |
236 | | - * console.log(`Committed version ${result.version} with ${result.events} events`) |
237 | | - * ``` |
238 | | - */ |
239 | | -export async function writeEventsDelta( |
240 | | - bucket: R2Bucket, |
241 | | - events: EventRecord[], |
242 | | - shardId: number = 0 |
243 | | -): Promise<DeltaWriteResult> { |
244 | | - if (events.length === 0) { |
245 | | - throw new Error('No events to write') |
246 | | - } |
247 | | - |
248 | | - const startCpu = performance.now() |
249 | | - |
250 | | - // Create storage backend from R2 bucket |
251 | | - const storage = createR2Storage(bucket) |
252 | | - |
253 | | - // Get or create the DeltaTable for this shard |
254 | | - const table = getDeltaTable(storage, shardId) |
255 | | - |
256 | | - // Convert events to DeltaLake format |
257 | | - const deltaRecords = events.map(toEventDeltaRecord) |
258 | | - |
259 | | - // Estimate bytes from serialized records (for metrics) |
260 | | - const estimatedBytes = deltaRecords.reduce((sum, record) => { |
261 | | - return sum + JSON.stringify(record).length |
262 | | - }, 0) |
263 | | - |
264 | | - // Write with ACID guarantees |
265 | | - const commit = await table.write(deltaRecords) |
266 | | - |
267 | | - const cpuMs = performance.now() - startCpu |
268 | | - const tablePath = getEventsTablePath(shardId) |
269 | | - |
270 | | - console.log(`[WRITE-DELTA] shard=${shardId} version=${commit.version} events=${events.length} cpuMs=${cpuMs.toFixed(2)}`) |
271 | | - |
272 | | - return { |
273 | | - version: commit.version, |
274 | | - events: events.length, |
275 | | - bytes: estimatedBytes, |
276 | | - path: `${tablePath}/_delta_log/${String(commit.version).padStart(20, '0')}.json`, |
277 | | - cpuMs, |
278 | | - } |
279 | | -} |
280 | | - |
281 | | -/** |
282 | | - * Write events using both legacy Parquet and DeltaLake (dual-write mode). |
283 | | - * |
284 | | - * This function writes to both storage formats during migration, ensuring |
285 | | - * data consistency and enabling gradual rollout of DeltaLake. |
286 | | - * |
287 | | - * @param bucket - R2 bucket for storage |
288 | | - * @param prefix - Legacy path prefix |
289 | | - * @param events - Events to write |
290 | | - * @param shardId - Shard ID for DeltaLake partitioning |
291 | | - * @returns Both legacy and DeltaLake results |
292 | | - */ |
293 | | -export async function writeEventsDualWrite( |
294 | | - bucket: R2Bucket, |
295 | | - prefix: string, |
296 | | - events: EventRecord[], |
297 | | - shardId: number = 0 |
298 | | -): Promise<{ legacy: WriteResult; delta: DeltaWriteResult }> { |
299 | | - // Write to both in parallel for performance |
300 | | - const [legacyResult, deltaResult] = await Promise.all([ |
301 | | - writeEvents(bucket, prefix, events), |
302 | | - writeEventsDelta(bucket, events, shardId), |
303 | | - ]) |
304 | | - |
305 | | - return { |
306 | | - legacy: legacyResult, |
307 | | - delta: deltaResult, |
308 | | - } |
309 | | -} |
310 | | - |
311 | 159 | // ============================================================================ |
312 | 160 | // Event Buffer - For batching events before writing |
313 | 161 | // ============================================================================ |
|
0 commit comments