Skip to content

Commit d1e21cc

Browse files
authored
Merge pull request #166 from spaghettidba/copilot/fix-primary-key-constraint-violation
Fix PRIMARY KEY violation in WorkloadDetails when interval fires multiple times
2 parents d3abc7e + 8413cc8 commit d1e21cc

File tree

1 file changed

+27
-3
lines changed

1 file changed

+27
-3
lines changed

WorkloadTools/Consumer/Analysis/WorkloadAnalyzer.cs

Lines changed: 27 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@ private class NormalizedQuery
6161

6262
private DateTime lastDump = DateTime.MinValue;
6363
private DateTime lastEventTime = DateTime.MinValue;
64+
private volatile int lastWrittenIntervalId = -1;
6465

6566
public WorkloadAnalyzer()
6667
{
@@ -88,6 +89,19 @@ private void CloseInterval()
8889
var duration = lastEventTime - lastDump;
8990
if (duration.TotalMinutes >= Interval)
9091
{
92+
// Avoid writing the same interval_id twice. This can happen when
93+
// Interval=0 (the default) and multiple events share the same
94+
// second-precision timestamp: after the first write sets
95+
// lastDump=lastEventTime, the condition above is 0>=0 (always true),
96+
// so the next loop iteration would attempt to INSERT to WorkloadDetails
97+
// for an interval_id that was already committed.
98+
var prospectiveIntervalId = ComputeIntervalId(lastEventTime);
99+
if (prospectiveIntervalId == lastWrittenIntervalId)
100+
{
101+
lastDump = lastEventTime;
102+
return;
103+
}
104+
91105
try
92106
{
93107
var numRetries = 0;
@@ -492,8 +506,9 @@ private void WriteToServer(DateTime intervalTime)
492506
{
493507
WriteExecutionDetails(conn, tran, current_interval_id);
494508
}
509+
510+
rawData.Clear();
495511
}
496-
rawData.Clear();
497512

498513
if (WriteDetail)
499514
{
@@ -505,6 +520,10 @@ private void WriteToServer(DateTime intervalTime)
505520
}
506521

507522
tran.Commit();
523+
if (WriteDetail)
524+
{
525+
lastWrittenIntervalId = current_interval_id;
526+
}
508527
}
509528
catch(Exception)
510529
{
@@ -1075,6 +1094,12 @@ private void InvokeGC()
10751094
GC.WaitForPendingFinalizers();
10761095
}
10771096

1097+
private int ComputeIntervalId(DateTime intervalTime)
1098+
{
1099+
// interval id is the number of seconds since 01/01/2000
1100+
return (int)intervalTime.Subtract(DateTime.MinValue.AddYears(1999)).TotalSeconds;
1101+
}
1102+
10781103
private int CreateInterval(SqlConnection conn, SqlTransaction tran, DateTime intervalTime)
10791104
{
10801105
var sql = @"
@@ -1089,8 +1114,7 @@ UPDATE [{0}].[Intervals]
10891114
";
10901115
sql = string.Format(sql, ConnectionInfo.SchemaName);
10911116

1092-
// interval id is the number of seconds since 01/01/2000
1093-
var interval_id = (int)intervalTime.Subtract(DateTime.MinValue.AddYears(1999)).TotalSeconds;
1117+
var interval_id = ComputeIntervalId(intervalTime);
10941118

10951119
using (var cmd = conn.CreateCommand())
10961120
{

0 commit comments

Comments
 (0)