1+ //------------------------------------------------------------
2+ // Copyright (c) Microsoft Corporation. All rights reserved.
3+ //------------------------------------------------------------
4+ namespace Microsoft . Azure . Cosmos
5+ {
6+ using System ;
7+ using System . Collections . Concurrent ;
8+ using System . Collections . Generic ;
9+ using Microsoft . Azure . Documents ;
10+
11+ internal class ProxyRequest
12+ {
13+ private static readonly int [ ] expectedPositionsForTokensDuringReorder ;
14+ private static readonly int [ ] positionsOfTokensToMakeOptionalAfterReorder ;
15+ private static readonly Action < RntbdToken , RntbdConstants . Request > [ ] settersForFieldsToMakeOptional ;
16+
17+ static ProxyRequest ( )
18+ {
19+ // Proxy expects the first tokens to be the ones needed for routing
20+ // This is done as an optimization to avoid parsing the entire request to get the routing and authorization information
21+ RntbdConstants . RequestIdentifiers [ ] firstTokenTypes = new [ ]
22+ {
23+ // Proxy expects EPK to be first
24+ RntbdConstants . RequestIdentifiers . EffectivePartitionKey ,
25+
26+ // The rest of the tokens that Proxy uses are moved to first positions for faster parsing in Proxy side
27+ RntbdConstants . RequestIdentifiers . StartEpkHash ,
28+ RntbdConstants . RequestIdentifiers . EndEpkHash ,
29+ RntbdConstants . RequestIdentifiers . GlobalDatabaseAccountName ,
30+ RntbdConstants . RequestIdentifiers . DatabaseName ,
31+ RntbdConstants . RequestIdentifiers . CollectionName ,
32+ RntbdConstants . RequestIdentifiers . CollectionRid ,
33+ RntbdConstants . RequestIdentifiers . ResourceId ,
34+
35+ // Fields used for AuthZ
36+ RntbdConstants . RequestIdentifiers . PayloadPresent ,
37+ RntbdConstants . RequestIdentifiers . DocumentName ,
38+ RntbdConstants . RequestIdentifiers . AuthorizationToken ,
39+ RntbdConstants . RequestIdentifiers . Date ,
40+ } ;
41+
42+ ( RntbdConstants . RequestIdentifiers , Action < RntbdToken , RntbdConstants . Request > ) [ ] tokensToMakeOptional = new ( RntbdConstants . RequestIdentifiers , Action < RntbdToken , RntbdConstants . Request > ) [ ]
43+ {
44+ // For Proxy, transportRequestId and replicapath are optional.
45+ ( RntbdConstants . RequestIdentifiers . ReplicaPath , ( token , request ) => request . replicaPath = token ) ,
46+ ( RntbdConstants . RequestIdentifiers . TransportRequestID , ( token , request ) => request . transportRequestID = token ) ,
47+ } ;
48+
49+ ProxyRequest . expectedPositionsForTokensDuringReorder = new int [ firstTokenTypes . Length ] ;
50+ RntbdConstants . Request rntbdRequest = new ( ) ;
51+ for ( int i = 0 ; i < firstTokenTypes . Length ; i ++ )
52+ {
53+ RntbdConstants . RequestIdentifiers tokenType = firstTokenTypes [ i ] ;
54+ int index = Array . FindIndex ( rntbdRequest . tokens , x => x ? . GetTokenIdentifier ( ) == ( ushort ) tokenType ) ;
55+ ProxyRequest . expectedPositionsForTokensDuringReorder [ i ] = index ;
56+ ProxyRequest . SwapTokens ( rntbdRequest . tokens , i , index ) ;
57+ }
58+
59+ Dictionary < RntbdConstants . RequestIdentifiers , int > indexes = new ( ) ;
60+ for ( int i = 0 ; i < rntbdRequest . tokens . Length ; i ++ )
61+ {
62+ if ( rntbdRequest . tokens [ i ] == null )
63+ {
64+ continue ;
65+ }
66+
67+ RntbdConstants . RequestIdentifiers tokenType = ( RntbdConstants . RequestIdentifiers ) rntbdRequest . tokens [ i ] . GetTokenIdentifier ( ) ;
68+ indexes [ tokenType ] = i ;
69+ }
70+
71+ ProxyRequest . positionsOfTokensToMakeOptionalAfterReorder = new int [ tokensToMakeOptional . Length ] ;
72+ ProxyRequest . settersForFieldsToMakeOptional = new Action < RntbdToken , RntbdConstants . Request > [ tokensToMakeOptional . Length ] ;
73+ for ( int i = 0 ; i < tokensToMakeOptional . Length ; i ++ )
74+ {
75+ ProxyRequest . positionsOfTokensToMakeOptionalAfterReorder [ i ] = indexes [ tokensToMakeOptional [ i ] . Item1 ] ;
76+ ProxyRequest . settersForFieldsToMakeOptional [ i ] = tokensToMakeOptional [ i ] . Item2 ;
77+ }
78+ }
79+
80+ public RntbdConstants . Request RntbdRequest { get ; } = new ( ) ;
81+ public ProxyRequest ( )
82+ {
83+ for ( int i = 0 ; i < ProxyRequest . expectedPositionsForTokensDuringReorder . Length ; i ++ )
84+ {
85+ ProxyRequest . SwapTokens ( this . RntbdRequest . tokens , i , ProxyRequest . expectedPositionsForTokensDuringReorder [ i ] ) ;
86+ }
87+
88+ // Make optional
89+ for ( int i = 0 ; i < ProxyRequest . positionsOfTokensToMakeOptionalAfterReorder . Length ; i ++ )
90+ {
91+ int expectedTokenPosition = ProxyRequest . positionsOfTokensToMakeOptionalAfterReorder [ i ] ;
92+ RntbdToken originalToken = this . RntbdRequest . tokens [ expectedTokenPosition ] ;
93+ this . RntbdRequest . tokens [ expectedTokenPosition ] = new RntbdToken ( false , originalToken . GetTokenType ( ) , originalToken . GetTokenIdentifier ( ) ) ;
94+ ProxyRequest . settersForFieldsToMakeOptional [ i ] ( this . RntbdRequest . tokens [ expectedTokenPosition ] , this . RntbdRequest ) ;
95+ }
96+ }
97+
98+ public void Reset ( )
99+ {
100+ this . RntbdRequest . Reset ( ) ;
101+ }
102+
103+ private static void SwapTokens ( RntbdToken [ ] tokens , int i , int j )
104+ {
105+ if ( i != j )
106+ {
107+ ( tokens [ j ] , tokens [ i ] ) = ( tokens [ i ] , tokens [ j ] ) ;
108+ }
109+ }
110+
111+ internal sealed class ObjectPool
112+ {
113+ public static readonly ObjectPool Instance = new ObjectPool ( ) ;
114+
115+ private readonly ConcurrentQueue < ProxyRequest > entities = new ConcurrentQueue < ProxyRequest > ( ) ;
116+
117+ private ObjectPool ( )
118+ {
119+ }
120+
121+ public EntityOwner Get ( )
122+ {
123+ if ( this . entities . TryDequeue ( out ProxyRequest entity ) )
124+ {
125+ return new EntityOwner ( entity ) ;
126+ }
127+
128+ return new EntityOwner ( new ProxyRequest ( ) ) ;
129+ }
130+
131+ private void Return ( ProxyRequest entity )
132+ {
133+ entity . Reset ( ) ;
134+ this . entities . Enqueue ( entity ) ;
135+ }
136+
137+ public readonly struct EntityOwner : IDisposable
138+ {
139+ public EntityOwner ( ProxyRequest entity )
140+ {
141+ this . Entity = entity ;
142+ }
143+
144+ public ProxyRequest Entity { get ; }
145+
146+ public void Dispose ( )
147+ {
148+ if ( this . Entity != null )
149+ {
150+ ObjectPool . Instance . Return ( this . Entity ) ;
151+ }
152+ }
153+ }
154+ }
155+ }
156+ }
0 commit comments