@@ -36,44 +36,49 @@ class ImapTokenCache
3636
3737 readonly Dictionary < ImapTokenKey , LinkedListNode < ImapTokenItem > > cache ;
3838 readonly LinkedList < ImapTokenItem > list ;
39+ readonly ImapTokenKey lookupKey ;
3940
4041 public ImapTokenCache ( )
4142 {
4243 cache = new Dictionary < ImapTokenKey , LinkedListNode < ImapTokenItem > > ( ) ;
4344 list = new LinkedList < ImapTokenItem > ( ) ;
45+ lookupKey = new ImapTokenKey ( ) ;
4446 }
4547
4648 public ImapToken AddOrGet ( ImapTokenType type , ByteArrayBuilder builder )
4749 {
48- // Note: This ImapTokenKey .ctor does not duplicate the buffer and is meant as a temporary key
49- // in order to avoid memory allocations for lookup purposes.
50- var key = new ImapTokenKey ( builder . GetBuffer ( ) , builder . Length ) ;
51-
5250 lock ( cache ) {
53- if ( cache . TryGetValue ( key , out var node ) ) {
51+ // lookupKey is a pre-allocated key used for lookups
52+ lookupKey . Init ( type , builder . GetBuffer ( ) , builder . Length ) ;
53+
54+ if ( cache . TryGetValue ( lookupKey , out var node ) ) {
5455 // move the node to the head of the list
5556 list . Remove ( node ) ;
5657 list . AddFirst ( node ) ;
58+ node . Value . Count ++ ;
5759
5860 return node . Value . Token ;
5961 }
6062
63+ var token = new ImapToken ( type , builder . ToString ( ) ) ;
64+
6165 if ( cache . Count >= capacity ) {
6266 // remove the least recently used token
6367 node = list . Last ;
6468 list . RemoveLast ( ) ;
6569 cache . Remove ( node . Value . Key ) ;
66- }
6770
68- var token = new ImapToken ( type , builder . ToString ( ) ) ;
69-
70- // Note: We recreate the key here so we have a permanent key. Also this allows for reuse of the token's Value string.
71- key = new ImapTokenKey ( ( string ) token . Value ) ;
71+ // re-use the node, item and key to avoid allocations
72+ node . Value . Key . Init ( type , ( string ) token . Value ) ;
73+ node . Value . Token = token ;
74+ } else {
75+ var key = new ImapTokenKey ( type , ( string ) token . Value ) ;
76+ var item = new ImapTokenItem ( key , token ) ;
7277
73- var item = new ImapTokenItem ( key , token ) ;
78+ node = new LinkedListNode < ImapTokenItem > ( item ) ;
79+ }
7480
75- node = new LinkedListNode < ImapTokenItem > ( item ) ;
76- cache . Add ( key , node ) ;
81+ cache . Add ( node . Value . Key , node ) ;
7782 list . AddFirst ( node ) ;
7883
7984 return token ;
@@ -82,33 +87,49 @@ public ImapToken AddOrGet (ImapTokenType type, ByteArrayBuilder builder)
8287
8388 class ImapTokenKey
8489 {
85- readonly byte [ ] byteArrayKey ;
86- readonly string stringKey ;
87- readonly int length ;
88- readonly int hashCode ;
90+ ImapTokenType type ;
91+ byte [ ] byteArrayKey ;
92+ string stringKey ;
93+ int length ;
94+ int hashCode ;
95+
96+ public ImapTokenKey ( )
97+ {
98+ }
8999
90- public ImapTokenKey ( byte [ ] key , int len )
100+ public ImapTokenKey ( ImapTokenType type , string key )
91101 {
92- byteArrayKey = key ;
93- length = len ;
102+ Init ( type , key ) ;
103+ }
104+
105+ public void Init ( ImapTokenType type , byte [ ] key , int length )
106+ {
107+ this . type = type ;
108+ this . byteArrayKey = key ;
109+ this . stringKey = null ;
110+ this . length = length ;
94111
95112 var hash = new HashCode ( ) ;
113+ hash . Add ( ( int ) type ) ;
96114 for ( int i = 0 ; i < length ; i ++ )
97115 hash . Add ( ( char ) key [ i ] ) ;
98116
99- hashCode = hash . ToHashCode ( ) ;
117+ this . hashCode = hash . ToHashCode ( ) ;
100118 }
101119
102- public ImapTokenKey ( string key )
120+ public void Init ( ImapTokenType type , string key )
103121 {
104- stringKey = key ;
105- length = key . Length ;
122+ this . type = type ;
123+ this . byteArrayKey = null ;
124+ this . stringKey = key ;
125+ this . length = key . Length ;
106126
107127 var hash = new HashCode ( ) ;
128+ hash . Add ( ( int ) type ) ;
108129 for ( int i = 0 ; i < length ; i ++ )
109130 hash . Add ( key [ i ] ) ;
110131
111- hashCode = hash . ToHashCode ( ) ;
132+ this . hashCode = hash . ToHashCode ( ) ;
112133 }
113134
114135 static bool Equals ( string str , byte [ ] bytes )
@@ -123,7 +144,7 @@ static bool Equals (string str, byte[] bytes)
123144
124145 static bool Equals ( ImapTokenKey self , ImapTokenKey other )
125146 {
126- if ( self . length != other . length )
147+ if ( self . type != other . type || self . length != other . length )
127148 return false ;
128149
129150 if ( self . stringKey != null ) {
@@ -153,17 +174,29 @@ public override int GetHashCode ()
153174 {
154175 return hashCode ;
155176 }
177+
178+ public override string ToString ( )
179+ {
180+ return string . Format ( "{0}: {1}" , type , stringKey ?? Encoding . UTF8 . GetString ( byteArrayKey , 0 , length ) ) ;
181+ }
156182 }
157183
158184 class ImapTokenItem
159185 {
160- public readonly ImapTokenKey Key ;
161- public readonly ImapToken Token ;
186+ public ImapTokenKey Key ;
187+ public ImapToken Token ;
188+ public int Count ;
162189
163190 public ImapTokenItem ( ImapTokenKey key , ImapToken token )
164191 {
165192 Key = key ;
166193 Token = token ;
194+ Count = 1 ;
195+ }
196+
197+ public override string ToString ( )
198+ {
199+ return $ "{ Count } ";
167200 }
168201 }
169202 }
0 commit comments