Skip to content

Add coverage for generic state parameter using Azure Storage (after #1897) - #1915

Merged
ReubenBond merged 4 commits into
dotnet:masterfrom
jdom:generic-arguments-bug-cleanup
Mar 22, 2017
Merged

ReubenBond merged 4 commits into
dotnet:masterfrom
jdom:generic-arguments-bug-cleanup

Conversation

@jdom

@jdom jdom commented Jul 8, 2016

Copy link
Copy Markdown
Member

While I was doing this minor cleanup, I encountered that this is still failing on the call to ClearState.
@Maarten88 do you know if this is still related to the grain type name or is this a new bug?

Both tests (with long and short name) are now failing, these are the details:

Test Name:  UnitTests.General.GenericGrainsInAzureStorageTests.Generic_OnAzureTableStorage_LongNamedGrain_EchoValue
Test FullName:  UnitTests.General.GenericGrainsInAzureStorageTests.Generic_OnAzureTableStorage_LongNamedGrain_EchoValue
Test Source:    D:\projects\OrleansVso\test\Tester\GenericGrainsInAzureStorageTests.cs : line 28
Test Outcome:   Failed
Test Duration:  0:00:00.286

Result StackTrace:  
Server stack trace: 
   at Orleans.Core.GrainStateStorageBridge.<ClearStateAsync>d__7.MoveNext() in D:\projects\OrleansVso\src\Orleans\Core\GrainStateStorageBridge.cs:line 147
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at UnitTests.Grains.SimpleGenericGrainUsingAzureTableStorage`1.<ClearState>d__1.MoveNext() in D:\projects\OrleansVso\test\TestGrains\GenericGrains.cs:line 69
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.PublicOrleansTaskExtensions.<BoxAwait>d__7.MoveNext() in D:\projects\OrleansVso\src\Orleans\Async\TaskExtensions.cs:line 128
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Orleans.Runtime.InsideRuntimeClient.<Invoke>d__57.MoveNext() in D:\projects\OrleansVso\src\OrleansRuntime\Core\InsideRuntimeClient.cs:line 395

Exception rethrown at [0]: 
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at UnitTests.General.GenericGrainsInAzureStorageTests.<Generic_OnAzureTableStorage_LongNamedGrain_EchoValue>d__1.MoveNext() in D:\projects\OrleansVso\test\Tester\GenericGrainsInAzureStorageTests.cs:line 32
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
----- Inner Stack Trace -----
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndExecuteAsync[T](IAsyncResult result)
   at Microsoft.WindowsAzure.Storage.Table.CloudTable.EndExecute(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Orleans.AzureUtils.AzureTableDataManager`1.<UpdateTableEntryAsync>d__21.MoveNext() in D:\projects\OrleansVso\src\OrleansAzureUtils\Storage\AzureTableDataManager.cs:line 305
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Orleans.Storage.AzureTableStorage.GrainStateTableDataManager.<Write>d__9.MoveNext() in D:\projects\OrleansVso\src\OrleansAzureUtils\Providers\Storage\AzureTableStorage.cs:line 500
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Orleans.Storage.AzureTableStorage.<ClearStateAsync>d__33.MoveNext() in D:\projects\OrleansVso\src\OrleansAzureUtils\Providers\Storage\AzureTableStorage.cs:line 221
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Core.GrainStateStorageBridge.<ClearStateAsync>d__7.MoveNext() in D:\projects\OrleansVso\src\Orleans\Core\GrainStateStorageBridge.cs:line 133
----- Inner Stack Trace -----
   at Microsoft.WindowsAzure.Storage.Table.Protocol.TableOperationHttpResponseParsers.TableOperationPreProcess(TableResult result, TableOperation operation, HttpWebResponse resp, Exception ex)
   at Microsoft.WindowsAzure.Storage.Table.TableOperation.<>c__DisplayClass13.<ReplaceImpl>b__12(RESTCommand`1 cmd, HttpWebResponse resp, Exception ex, OperationContext ctx)
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndGetResponse[T](IAsyncResult getResponseResult)
Result Message: 
Orleans.Runtime.OrleansException : Error from storage provider during ClearState for grain Type=UnitTests.Grains.SimpleGenericGrainUsingAzureTableStorage`1[[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]] Pk=*grn/F4F91C41/4226a67b4367d6461eedf64f82301bad0303c6e2f4f91c41-0xC9D474F8 Id=GrainReference:*grn/F4F91C41/82301bad<[System.Int32, mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089]> Error=

Exc level 0: Microsoft.WindowsAzure.Storage.StorageException: The remote server returned an error: (400) Bad Request.
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndExecuteAsync[T](IAsyncResult result)
   at Microsoft.WindowsAzure.Storage.Table.CloudTable.EndExecute(IAsyncResult asyncResult)
   at System.Threading.Tasks.TaskFactory`1.FromAsyncCoreLogic(IAsyncResult iar, Func`2 endFunction, Action`1 endAction, Task`1 promise, Boolean requiresSynchronization)
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
   at Orleans.AzureUtils.AzureTableDataManager`1.<UpdateTableEntryAsync>d__21.MoveNext() in D:\projects\OrleansVso\src\OrleansAzureUtils\Storage\AzureTableDataManager.cs:line 305
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable`1.ConfiguredTaskAwaiter.GetResult()
   at Orleans.Storage.AzureTableStorage.GrainStateTableDataManager.<Write>d__9.MoveNext() in D:\projects\OrleansVso\src\OrleansAzureUtils\Providers\Storage\AzureTableStorage.cs:line 500
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.ConfiguredTaskAwaitable.ConfiguredTaskAwaiter.GetResult()
   at Orleans.Storage.AzureTableStorage.<ClearStateAsync>d__33.MoveNext() in D:\projects\OrleansVso\src\OrleansAzureUtils\Providers\Storage\AzureTableStorage.cs:line 221
--- End of stack trace from previous location where exception was thrown ---
   at System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
   at System.Runtime.CompilerServices.TaskAwaiter.GetResult()
   at Orleans.Core.GrainStateStorageBridge.<ClearStateAsync>d__7.MoveNext() in D:\projects\OrleansVso\src\Orleans\Core\GrainStateStorageBridge.cs:line 133
Exc level 1: System.Net.WebException: The remote server returned an error: (400) Bad Request.
   at Microsoft.WindowsAzure.Storage.Table.Protocol.TableOperationHttpResponseParsers.TableOperationPreProcess(TableResult result, TableOperation operation, HttpWebResponse resp, Exception ex)
   at Microsoft.WindowsAzure.Storage.Table.TableOperation.<>c__DisplayClass13.<ReplaceImpl>b__12(RESTCommand`1 cmd, HttpWebResponse resp, Exception ex, OperationContext ctx)
   at Microsoft.WindowsAzure.Storage.Core.Executor.Executor.EndGetResponse[T](IAsyncResult getResponseResult)
---- Microsoft.WindowsAzure.Storage.StorageException : The remote server returned an error: (400) Bad Request.
-------- System.Net.WebException : The remote server returned an error: (400) Bad Request.

@Maarten88

Copy link
Copy Markdown
Contributor

There is still a problem with TableStorage on generic grains. But I'd expect not only ClearState to fail, but ReadState and WriteState as well. The problem is that the grainType contains the generic parameters as fully qualified types (including assembly info) instead of just the base type names.

The Table Storage Provider then does grainReference.ToKeyString(), which creates a string that, in the case of a generic grain, adds the complete generictype in the key string, creating a partitionkey that is too long; TableStorage does not accept it.

Simplest solution would be to change the ToKeyString() function to return a more compact string for generic grain. A better solution would be to fix the whole internal handling of generic grain type names to not use type.FullName anymore, but type.ToString() or TypeUtils.GetParseableName()

@Maarten88

Maarten88 commented Jul 8, 2016 •

Copy link
Copy Markdown
Contributor

I am debugging this; I'm completely at loss why ClearState behaves differently from ReadState and WriteState. It seems the culprit is somewhere in the rowkey value: Azure Table Storage does not like the value in it (which is the grainType), but only in Replace and Delete table operations. Insert and Read seem to work fine with the same values!

Sanitizing the row key with AzureStorageUtils.SanitizeTableProperty() does not help. Putting the base type in the rowKey also does not work. But simply making it empty does help! Maybe there's a limitation on the combined length of partitionKey and rowKey? I can't find good documentation on this; only speculation in forums.

Simplest solution would be to do away with the rowkey completely as it's not helping anyway, but for backwards compatibility it's probably wiser to keep the grainType in there for non-generic grains and make it empty for generic grains (breaking generic state partition key will happen anyway now, so we can break the rowkey too)

@veikkoeeva

veikkoeeva commented Jul 8, 2016 •

Copy link
Copy Markdown
Contributor

@Maarten88, @jdom Just in case, I note here that relational storage provider needs a enough data in grainType (or then glance it from the grain reference) to either use straight away or allow to get enough consistent data out of it so as to create the type key consistently (the ClearState won't work otherwise, which seem to be different compared to ATS here as currently there aren't problems).

@Maarten88

Copy link
Copy Markdown
Contributor

I found some recent documentation on differences between Azure Storage and Storage Emulator that might help here: https://docs.microsoft.com/en-gb/azure/storage/storage-use-emulator

specifically:

  • The storage emulator supports partition key and row key property values of less than 512 bytes each. Additionally, the total size of the account name, table name, and key property names together cannot exceed 900 bytes.

@sergeybykov sergeybykov modified the milestones: 1.5.0, 1.4.0 Jan 14, 2017
@jdom
jdom force-pushed the generic-arguments-bug-cleanup branch from 49bbb08 to 1582af0 Compare March 22, 2017 02:23
@jdom

jdom commented Mar 22, 2017 •

Copy link
Copy Markdown
Member Author

Rebased this (since there were many conflicts) and added a way to skip the tests if they are being run from the emulator, given the differences in combined property lengths supported in comparison with the production service.
These tests are all passing now (or skipped when real azure storage is not configured)

@jdom jdom changed the title WIP: Cleanup for PR #1897 (generic state parameter bug) Cleanup for PR #1897 (generic state parameter bug) Mar 22, 2017
@jdom
jdom requested a review from ReubenBond March 22, 2017 02:37
@jdom
jdom removed the request for review from ReubenBond March 22, 2017 02:38
@ReubenBond

Copy link
Copy Markdown
Member

This ought to have been fixed by #2715. I'll take a look and merge

@jdom

jdom commented Mar 22, 2017 •

Copy link
Copy Markdown
Member Author

Could be, not sure, I did not run it again before rebase, but after the rebase I was still seeing the same stack trace on ClearState that failed the test, when running the test using the storage emulator. So I assume this was just a test issue.

@jdom jdom changed the title Cleanup for PR #1897 (generic state parameter bug) Add coverage for generic state parameter using Azure Storage (after #1897) Mar 22, 2017
@ReubenBond

Copy link
Copy Markdown
Member

Ok, so it seems that blob names can be at most 261 characters when using the Azure Storage Emulator. If I truncate the name to 260 chars, then I get a 404 instead of a 400.

@ReubenBond
ReubenBond merged commit 7a29756 into dotnet:master Mar 22, 2017
@jdom
jdom deleted the generic-arguments-bug-cleanup branch March 22, 2017 17:40
@github-actions github-actions Bot locked and limited conversation to collaborators Dec 12, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants