Skip to content

Commit 4baf194

Browse files
GetLeaseLockedRows for debug logging (#900)
* add isLeaseLocked into the getchanges query * add log message * add debug logging for row counts * update log msg * create a separate query for getting the locked rows * update ver name * update * remove user table join * unused var * correct xml info * address comments * remove extra line * dont throw * Update src/TriggerBinding/SqlTableChangeMonitor.cs Co-authored-by: Charles Gagnon <[email protected]> --------- Co-authored-by: Charles Gagnon <[email protected]>
1 parent d77979f commit 4baf194

File tree

2 files changed

+56
-1
lines changed

2 files changed

+56
-1
lines changed

src/Telemetry/Telemetry.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,7 @@ public enum TelemetryMeasureName
390390
GetColumnDefinitionsDurationMs,
391391
GetPrimaryKeysDurationMs,
392392
GetUnprocessedChangesDurationMs,
393+
GetLockedRowCountDurationMs,
393394
InsertGlobalStateTableRowDurationMs,
394395
MaxBatchSize,
395396
MaxChangesPerWorker,
@@ -437,6 +438,7 @@ public enum TelemetryErrorName
437438
Upsert,
438439
UpsertRollback,
439440
GetServerTelemetryProperties,
441+
GetLeaseLockedRowCount,
440442
}
441443

442444
internal class ServerProperties

src/TriggerBinding/SqlTableChangeMonitor.cs

Lines changed: 54 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,15 @@ private async Task GetTableChangesAsync(SqlConnection connection, CancellationTo
305305

306306
getChangesDurationMs = commandSw.ElapsedMilliseconds;
307307
}
308-
308+
// Also get the number of rows that currently have lease locks on them
309+
// This can help with supportability by allowing a customer to see when a
310+
// trigger was processed successfully but returned fewer rows than expected
311+
// because of the rows being locked.
312+
int leaseLockedRowCount = await this.GetLeaseLockedRowCount(connection, transaction);
313+
if (rows.Count > 0 || leaseLockedRowCount > 0)
314+
{
315+
this._logger.LogDebug($"Executed GetChangesCommand in GetTableChangesAsync. {rows.Count} available changed rows ({leaseLockedRowCount} found with lease locks).");
316+
}
309317
// If changes were found, acquire leases on them.
310318
if (rows.Count > 0)
311319
{
@@ -810,6 +818,51 @@ LEFT OUTER JOIN {this._userTable.BracketQuotedFullName} AS u ON {userTableJoinCo
810818
return new SqlCommand(getChangesQuery, connection, transaction);
811819
}
812820

821+
/// <summary>
822+
/// Returns the number of changes(rows) on the user's table that are actively locked by other leases OR returns -1 on exception.
823+
/// </summary>
824+
/// <param name="connection">The connection to add to the SqlCommand</param>
825+
/// <param name="transaction">The transaction to add to the SqlCommand</param>
826+
/// <returns>The number of rows locked by leases or -1 on exception</returns>
827+
private async Task<int> GetLeaseLockedRowCount(SqlConnection connection, SqlTransaction transaction)
828+
{
829+
string leasesTableJoinCondition = string.Join(" AND ", this._primaryKeyColumns.Select(col => $"c.{col.name.AsBracketQuotedString()} = l.{col.name.AsBracketQuotedString()}"));
830+
int leaseLockedRowsCount = 0;
831+
long getLockedRowCountDurationMs = 0L;
832+
// Get the count of changes from CHANGETABLE that meet the following criteria:
833+
// * Not Null LeaseExpirationTime AND
834+
// * LeaseExpirationTime > Current Time
835+
string getLeaseLockedrowCountQuery = $@"
836+
{AppLockStatements}
837+
838+
DECLARE @last_sync_version bigint;
839+
SELECT @last_sync_version = LastSyncVersion
840+
FROM {GlobalStateTableName}
841+
WHERE UserFunctionID = '{this._userFunctionId}' AND UserTableID = {this._userTableId};
842+
843+
SELECT COUNT(*)
844+
FROM CHANGETABLE(CHANGES {this._userTable.BracketQuotedFullName}, @last_sync_version) AS c
845+
LEFT OUTER JOIN {this._leasesTableName} AS l ON {leasesTableJoinCondition}
846+
WHERE l.{LeasesTableLeaseExpirationTimeColumnName} IS NOT NULL AND l.{LeasesTableLeaseExpirationTimeColumnName} > SYSDATETIME()";
847+
try
848+
{
849+
using (var getLeaseLockedRowCountCommand = new SqlCommand(getLeaseLockedrowCountQuery, connection, transaction))
850+
{
851+
var commandSw = Stopwatch.StartNew();
852+
leaseLockedRowsCount = (int)await getLeaseLockedRowCountCommand.ExecuteScalarAsyncWithLogging(this._logger, CancellationToken.None);
853+
getLockedRowCountDurationMs = commandSw.ElapsedMilliseconds;
854+
}
855+
}
856+
catch (Exception ex)
857+
{
858+
this._logger.LogError($"Failed to query count of lease locked changes for table '{this._userTable.FullName}' due to exception: {ex.GetType()}. Exception message: {ex.Message}");
859+
TelemetryInstance.TrackException(TelemetryErrorName.GetLeaseLockedRowCount, ex, null, new Dictionary<TelemetryMeasureName, double>() { { TelemetryMeasureName.GetLockedRowCountDurationMs, getLockedRowCountDurationMs } });
860+
// This is currently only used for debugging, so return a -1 instead of throwing since it isn't necessary to get the value
861+
leaseLockedRowsCount = -1;
862+
}
863+
return leaseLockedRowsCount;
864+
}
865+
813866
/// <summary>
814867
/// Builds the query to acquire leases on the rows in "_rows" if changes are detected in the user's table
815868
/// (<see cref="RunChangeConsumptionLoopAsync()"/>).

0 commit comments

Comments
 (0)