/// <summary> /// Utility function used by async tests /// </summary> /// <param name="rnd"> Used to randomize reader.Read() call, whether it should continue or break, and is passed down to ConsumeReaderAsync</param> /// <param name="result"> The Async result from Begin operation.</param> /// <param name="com"> The Sql Command to Execute</param> /// <param name="query">Indicates if data is being queried and where ExecuteQuery or Non-query to be used with the reader</param> /// <param name="xml">Indicates if the query should be executed as an Xml</param> /// <param name="cancelled">Indicates if command was cancelled and is used to throw exception if a Command cancelation related exception is encountered</param> /// <param name="cts">The Cancellation Token Source</param> private void SqlCommandEndExecute(Random rnd, IAsyncResult result, SqlCommand com, bool query, bool xml, bool cancelled, CancellationTokenSource cts = null) { try { bool closeReader = ShouldCloseDataReader(); if (xml) { XmlReader reader = null; if (result != null && result is Task<XmlReader>) { reader = AsyncUtils.GetResult<XmlReader>(result); } else { reader = AsyncUtils.ExecuteXmlReader(com); } while (reader.Read()) { if (rnd.Next(10) == 0) break; if (rnd.Next(2) == 0) continue; reader.ReadElementContentAsString(); } if (closeReader) reader.Dispose(); } else if (query) { DataStressReader reader = null; if (result != null && result is Task<SqlDataReader>) { reader = new DataStressReader(AsyncUtils.GetResult<SqlDataReader>(result)); } else { reader = new DataStressReader(AsyncUtils.ExecuteReader(com)); } CancellationToken token = (cts != null) ? cts.Token : CancellationToken.None; AsyncUtils.WaitAndUnwrapException(ConsumeReaderAsync(reader, false, token, rnd)); if (closeReader) reader.Close(); } else { if (result != null && result is Task<int>) { int temp = AsyncUtils.GetResult<int>(result); } else { AsyncUtils.ExecuteNonQuery(com); } } } catch (Exception e) { if (cancelled && IsCommandCancelledException(e)) { // expected exception, ignore } else { throw; } } }
/// <summary> /// Utility function used by async tests /// </summary> /// <param name="rnd"> Used to randomize reader.Read() call, whether it should continue or break, and is passed down to ConsumeReaderAsync</param> /// <param name="result"> The Async result from Begin operation.</param> /// <param name="com"> The Sql Command to Execute</param> /// <param name="query">Indicates if data is being queried and where ExecuteQuery or Non-query to be used with the reader</param> /// <param name="xml">Indicates if the query should be executed as an Xml</param> /// <param name="cancelled">Indicates if command was cancelled and is used to throw exception if a Command cancellation related exception is encountered</param> /// <param name="cts">The Cancellation Token Source</param> private void SqlCommandEndExecute(Random rnd, IAsyncResult result, SqlCommand com, bool query, bool xml, bool cancelled, CancellationTokenSource cts = null) { try { bool closeReader = ShouldCloseDataReader(); if (xml) { XmlReader reader = null; if (result != null && result is Task <XmlReader> ) { reader = AsyncUtils.GetResult <XmlReader>(result); } else { reader = AsyncUtils.ExecuteXmlReader(com); } while (reader.Read()) { if (rnd.Next(10) == 0) { break; } if (rnd.Next(2) == 0) { continue; } reader.ReadElementContentAsString(); } if (closeReader) { reader.Dispose(); } } else if (query) { DataStressReader reader = null; if (result != null && result is Task <SqlDataReader> ) { reader = new DataStressReader(AsyncUtils.GetResult <SqlDataReader>(result)); } else { reader = new DataStressReader(AsyncUtils.ExecuteReader(com)); } CancellationToken token = (cts != null) ? cts.Token : CancellationToken.None; AsyncUtils.WaitAndUnwrapException(ConsumeReaderAsync(reader, false, token, rnd)); if (closeReader) { reader.Close(); } } else { if (result != null && result is Task <int> ) { int temp = AsyncUtils.GetResult <int>(result); } else { AsyncUtils.ExecuteNonQuery(com); } } } catch (Exception e) { if (cancelled && IsCommandCancelledException(e)) { // expected exception, ignore } else { throw; } } }
protected virtual async Task ConsumeCharsAsync(DataStressReader reader, int i, CancellationToken token, Random rnd) { char[] buffer = new char[255]; if (rnd.NextBool()) { // Read with GetChars reader.GetChars(i, rnd.Next(20), buffer, rnd.Next(20), rnd.Next(200)); } else if (reader.GetProviderSpecificFieldType(i) == typeof(SqlXml)) { // SqlClient only: Xml is read by XmlReader DataStressXmlReader xmlReader = reader.GetXmlReader(i); xmlReader.Read(); } else { // Read with TextReader DataStressTextReader textReader = reader.GetTextReader(i); if (rnd.NextBool()) { textReader.Peek(); } await textReader.ReadSyncOrAsync(buffer, rnd.Next(20), rnd.Next(200), rnd); if (rnd.NextBool()) { textReader.Peek(); } } }
protected virtual async Task ConsumeBytesAsync(DataStressReader reader, int i, CancellationToken token, Random rnd) { byte[] buffer = new byte[255]; if (rnd.NextBool()) { // We can optionally use GetBytes reader.GetBytes(i, rnd.Next(20), buffer, rnd.Next(20), rnd.Next(200)); } else if (reader.GetName(i) != "timestamp_FLD") { // Timestamp appears to be binary, but cannot be read by Stream DataStressStream stream = reader.GetStream(i); await stream.ReadSyncOrAsync(buffer, rnd.Next(20), rnd.Next(200), token, rnd); } else { // It is timestamp column, so read it later with GetValueSyncOrAsync await reader.GetValueSyncOrAsync(i, token, rnd); } }
/// <summary> /// Utility function to consume a single row of a reader in a random fashion after Read/ReadAsync has been invoked. /// </summary> protected virtual async Task ConsumeRowAsync(DataStressReader reader, bool sequentialAccess, CancellationToken token, Random rnd) { for (int i = 0; i < reader.FieldCount; i++) { if (rnd.Next(10) == 0) break; // stop reading from this row if (rnd.Next(2) == 0) continue; // skip this field bool hasBeenRead = false; // If the field is not null, we can optionally use streaming API if ((!await reader.IsDBNullSyncOrAsync(i, token, rnd)) && (rnd.NextBool())) { Type t = reader.GetFieldType(i); if (t == typeof(byte[])) { await ConsumeBytesAsync(reader, i, token, rnd); hasBeenRead = true; } else if (t == typeof(string)) { await ConsumeCharsAsync(reader, i, token, rnd); hasBeenRead = true; } } // If the field has not yet been read, or if it is non-sequential then we can re-read it if ((!hasBeenRead) || (!sequentialAccess)) { if (!await reader.IsDBNullSyncOrAsync(i, token, rnd)) { // Field value is not null, we can use new GetFieldValue<T> methods await reader.GetValueSyncOrAsync(i, token, rnd); } else { // Field value is null, we have to use old GetValue method reader.GetValue(i); } } // Do IsDBNull check again with 50% probability if (rnd.NextBool()) await reader.IsDBNullSyncOrAsync(i, token, rnd); } }
/// <summary> /// Utility function to consume a reader in a random fashion /// </summary> protected virtual async Task ConsumeReaderAsync(DataStressReader reader, bool sequentialAccess, CancellationToken token, Random rnd) { // Close 1/10 of readers while they are reading Task closeTask = null; if (AllowReaderCloseDuringReadAsync() && rnd.NextBool(0.1)) { // Begin closing now on another thread closeTask = reader.CloseAsync(); } try { do { while (await reader.ReadSyncOrAsync(token, rnd)) { // Optionally stop reading the current result set if (rnd.NextBool(0.1)) break; // Read the current row await ConsumeRowAsync(reader, sequentialAccess, token, rnd); } // Executing NextResult only 50% of the time if (rnd.NextBool()) break; } while (await reader.NextResultSyncOrAsync(token, rnd)); } catch (Exception e) { if (closeTask != null && IsReaderClosedException(e)) { // Catch reader closed exception } else { throw; } } finally { if (closeTask != null) AsyncUtils.WaitAndUnwrapException(closeTask); } }
protected async virtual Task CommandExecuteAsync(Random rnd, DbCommand com, bool query) { CancellationTokenSource cts = null; // Cancel 1/10 commands Task cancelTask = null; bool cancelCommand = rnd.NextBool(0.1); if (cancelCommand) { if (rnd.NextBool()) { // Use DbCommand.Cancel cancelTask = Task.Run(() => CommandCancel(com)); } else { // Use CancellationTokenSource if (cts == null) cts = new CancellationTokenSource(); cancelTask = Task.Run(() => cts.Cancel()); } } // Get the CancellationToken CancellationToken token = (cts != null) ? cts.Token : CancellationToken.None; DataStressReader reader = null; try { if (query) { CommandBehavior commandBehavior = CommandBehavior.Default; if (rnd.NextBool(0.5)) commandBehavior |= CommandBehavior.SequentialAccess; if (rnd.NextBool(0.25)) commandBehavior |= CommandBehavior.KeyInfo; if (rnd.NextBool(0.1)) commandBehavior |= CommandBehavior.SchemaOnly; // Get the reader reader = new DataStressReader(await com.ExecuteReaderSyncOrAsync(commandBehavior, token, rnd)); // Consume the reader's data await ConsumeReaderAsync(reader, commandBehavior.HasFlag(CommandBehavior.SequentialAccess), token, rnd); } else { await com.ExecuteNonQuerySyncOrAsync(token, rnd); } } catch (Exception e) { if (cancelCommand && IsCommandCancelledException(e)) { // Catch command canceled exception } else { throw; } } finally { if (cancelTask != null) AsyncUtils.WaitAndUnwrapException(cancelTask); if (reader != null && ShouldCloseDataReader()) reader.Close(); } }