@@ -33,8 +33,8 @@ public class PostgreSQLCorpus: ComponentBase, Corpus {
3333 private var fuzzerRegistered = false
3434 private var fuzzerId : Int ? // Master database fuzzer ID
3535
36- /// Batch execution storage
37- private var pendingExecutions : [ ( Program , ProgramAspects , DatabaseExecutionPurpose ) ] = [ ]
36+ /// Batch execution storage - includes execution metadata
37+ private var pendingExecutions : [ ( Program , ProgramAspects , DatabaseExecutionPurpose , ExecutionData ) ] = [ ]
3838 private var executionBatchSize : Int // Dynamic batch size
3939 private let executionBatchLock = NSLock ( )
4040
@@ -178,7 +178,7 @@ public class PostgreSQLCorpus: ComponentBase, Corpus {
178178 guard fuzzerId != nil else { return }
179179
180180 // Commit pending executions
181- let queuedExecutions = executionBatchLock. withLock {
181+ let queuedExecutions : [ ( Program , ProgramAspects , DatabaseExecutionPurpose , ExecutionData ) ] = executionBatchLock. withLock {
182182 let queuedExecutions = pendingExecutions
183183 pendingExecutions. removeAll ( )
184184 return queuedExecutions
@@ -390,10 +390,10 @@ public class PostgreSQLCorpus: ComponentBase, Corpus {
390390 }
391391
392392 /// Add execution to batch for later processing
393- private func addToExecutionBatch( _ program: Program , _ aspects: ProgramAspects , executionType: DatabaseExecutionPurpose ) {
393+ private func addToExecutionBatch( _ program: Program , _ aspects: ProgramAspects , executionType: DatabaseExecutionPurpose , executionData : ExecutionData ) {
394394 // Use atomic operations to avoid blocking locks
395- let shouldProcessBatch : [ ( Program , ProgramAspects , DatabaseExecutionPurpose ) ] ? = executionBatchLock. withLock {
396- pendingExecutions. append ( ( program, aspects, executionType) )
395+ let shouldProcessBatch : [ ( Program , ProgramAspects , DatabaseExecutionPurpose , ExecutionData ) ] ? = executionBatchLock. withLock {
396+ pendingExecutions. append ( ( program, aspects, executionType, executionData ) )
397397 let currentBatchSize = executionBatchSize
398398 let shouldProcess = pendingExecutions. count >= currentBatchSize
399399 if shouldProcess {
@@ -413,7 +413,7 @@ public class PostgreSQLCorpus: ComponentBase, Corpus {
413413 }
414414
415415 /// Process a batch of executions
416- private func processExecutionBatch( _ batch: [ ( Program , ProgramAspects , DatabaseExecutionPurpose ) ] ) async {
416+ private func processExecutionBatch( _ batch: [ ( Program , ProgramAspects , DatabaseExecutionPurpose , ExecutionData ) ] ) async {
417417 guard let fuzzerId = fuzzerId else {
418418 logger. error ( " Cannot process execution batch: fuzzer not registered " )
419419 return
@@ -428,7 +428,7 @@ public class PostgreSQLCorpus: ComponentBase, Corpus {
428428 var uniquePrograms : [ String : ( Program , ExecutionMetadata ) ] = [ : ]
429429 var executionBatchData : [ ExecutionBatchData ] = [ ]
430430
431- for (program, aspects, executionType) in batch {
431+ for (program, aspects, executionType, execData ) in batch {
432432 // Filter out test programs with FUZZILLI_CRASH (false positive crashes)
433433 if DatabaseUtils . containsFuzzilliCrash ( program: program) {
434434 if enableLogging {
@@ -464,7 +464,11 @@ public class PostgreSQLCorpus: ComponentBase, Corpus {
464464 mutatorType: nil ,
465465 outcome: aspects. outcome,
466466 coverage: coveragePct,
467- coverageEdges: ( aspects as? CovEdgeSet ) . map { Set ( $0. getEdges ( ) . map { Int ( $0) } ) } ?? Set < Int > ( )
467+ executionTimeMs: Int ( execData. execTime * 1000 ) ,
468+ coverageEdges: ( aspects as? CovEdgeSet ) . map { Set ( $0. getEdges ( ) . map { Int ( $0) } ) } ?? Set < Int > ( ) ,
469+ stdout: execData. stdout,
470+ stderr: execData. stderr,
471+ fuzzout: execData. fuzzout
468472 )
469473 executionBatchData. append ( executionData)
470474 }
@@ -491,7 +495,7 @@ public class PostgreSQLCorpus: ComponentBase, Corpus {
491495
492496 /// Flush any pending executions in the batch
493497 private func flushExecutionBatch( ) {
494- let batch = executionBatchLock. withLock {
498+ let batch : [ ( Program , ProgramAspects , DatabaseExecutionPurpose , ExecutionData ) ] = executionBatchLock. withLock {
495499 let batch = pendingExecutions
496500 pendingExecutions. removeAll ( )
497501 return batch
@@ -521,7 +525,7 @@ public class PostgreSQLCorpus: ComponentBase, Corpus {
521525 }
522526
523527 // Process any queued executions
524- let queuedExecutions = executionBatchLock. withLock {
528+ let queuedExecutions : [ ( Program , ProgramAspects , DatabaseExecutionPurpose , ExecutionData ) ] = executionBatchLock. withLock {
525529 let queuedExecutions = pendingExecutions
526530 pendingExecutions. removeAll ( )
527531 return queuedExecutions
@@ -681,53 +685,15 @@ public class PostgreSQLCorpus: ComponentBase, Corpus {
681685 return
682686 }
683687
684- do {
685- // Use the registered fuzzer ID
686- guard let fuzzerId = fuzzerId else {
687- if enableLogging {
688- self . logger. info ( " Cannot store execution: fuzzer not registered " )
689- }
690- return
691- }
692-
693- // DEBUG: Log execution storage attempt
694- if enableLogging {
695- self . logger. info ( " Storing execution: fuzzerId= \( fuzzerId) , outcome= \( executionData. outcome) , execTime= \( executionData. execTime) " )
696- }
697-
698- // Derive coverage percentage (0-100) from evaluator if available
699- let coveragePct : Double = {
700- if let coverageEvaluator = self . fuzzer. evaluator as? ProgramCoverageEvaluator {
701- return coverageEvaluator. currentScore * 100.0
702- } else {
703- return 0.0
704- }
705- } ( )
706-
707- // Store both program and execution in a single transaction to avoid foreign key issues
708- _ = try await storage. storeProgramAndExecution (
709- program: program,
710- fuzzerId: fuzzerId,
711- executionType: executionType,
712- outcome: executionData. outcome,
713- coverage: coveragePct,
714- executionTimeMs: Int ( executionData. execTime * 1000 ) ,
715- stdout: executionData. stdout,
716- stderr: executionData. stderr,
717- fuzzout: executionData. fuzzout,
718- metadata: ExecutionMetadata ( lastOutcome: DatabaseExecutionOutcome (
719- id: DatabaseUtils . mapExecutionOutcome ( outcome: aspects. outcome) ,
720- outcome: aspects. outcome. description,
721- description: aspects. outcome. description
722- ) )
723- )
724-
725- if enableLogging {
726- self . logger. info ( " Successfully stored program and execution " )
688+ // Add to execution batch for batched storage (even if fuzzer not registered yet)
689+ addToExecutionBatch ( program, aspects, executionType: executionType, executionData: executionData)
690+
691+ if enableLogging {
692+ if fuzzerId == nil {
693+ self . logger. info ( " Queued execution for later (fuzzer not registered yet) " )
694+ } else {
695+ self . logger. info ( " Added execution to batch: outcome= \( executionData. outcome) , execTime= \( executionData. execTime) " )
727696 }
728-
729- } catch {
730- logger. error ( " Failed to store execution: \( String ( reflecting: error) ) " )
731697 }
732698 }
733699
0 commit comments