~ubuntu-branches/ubuntu/trusty/smuxi/trusty-proposed

« back to all changes in this revision

Viewing changes to lib/ServiceStack/src/ServiceStack.Common/Net30/SplitOrderedList.cs

  • Committer: Package Import Robot
  • Author(s): Mirco Bauer
  • Date: 2013-05-25 22:11:31 UTC
  • mfrom: (1.2.12)
  • Revision ID: package-import@ubuntu.com-20130525221131-nd2mc0kzubuwyx20
Tags: 0.8.11-1
* [22d13d5] Imported Upstream version 0.8.11
* [6d2b95a] Refreshed patches
* [89eb66e] Added ServiceStack libraries to smuxi-engine package
* [848ab10] Enable Campfire engine
* [c6dbdc7] Always build db4o for predictable build result
* [13ec489] Exclude OS X specific libraries from dh_clideps

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
// SplitOrderedList.cs
 
2
//
 
3
// Copyright (c) 2010 Jérémie "Garuma" Laval
 
4
//
 
5
// Permission is hereby granted, free of charge, to any person obtaining a copy
 
6
// of this software and associated documentation files (the "Software"), to deal
 
7
// in the Software without restriction, including without limitation the rights
 
8
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 
9
// copies of the Software, and to permit persons to whom the Software is
 
10
// furnished to do so, subject to the following conditions:
 
11
//
 
12
// The above copyright notice and this permission notice shall be included in
 
13
// all copies or substantial portions of the Software.
 
14
//
 
15
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
16
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
17
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 
18
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 
19
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
20
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 
21
// THE SOFTWARE.
 
22
//
 
23
//
 
24
 
 
25
#if !NET_4_0 
 
26
 
 
27
using System;
 
28
using System.Threading;
 
29
using System.Collections;
 
30
using System.Collections.Generic;
 
31
using System.Runtime.Serialization;
 
32
 
 
33
namespace ServiceStack.Net30.Collections.Concurrent
 
34
{
 
35
    internal class SplitOrderedList<TKey, T>
 
36
    {
 
37
        class Node
 
38
        {
 
39
            public bool Marked;
 
40
            public ulong Key;
 
41
            public TKey SubKey;
 
42
            public T Data;
 
43
            public Node Next;
 
44
 
 
45
            public Node Init (ulong key, TKey subKey, T data)
 
46
            {
 
47
                this.Key = key;
 
48
                this.SubKey = subKey;
 
49
                this.Data = data;
 
50
 
 
51
                this.Marked = false;
 
52
                this.Next = null;
 
53
 
 
54
                return this;
 
55
            }
 
56
 
 
57
            // Used to create dummy node
 
58
            public Node Init (ulong key)
 
59
            {
 
60
                this.Key = key;
 
61
                this.Data = default (T);
 
62
 
 
63
                this.Next = null;
 
64
                this.Marked = false;
 
65
                this.SubKey = default (TKey);
 
66
 
 
67
                return this;
 
68
            }
 
69
 
 
70
            // Used to create marked node
 
71
            public Node Init (Node wrapped)
 
72
            {
 
73
                this.Marked = true;
 
74
                this.Next = wrapped;
 
75
 
 
76
                this.Key = 0;
 
77
                this.Data = default (T);
 
78
                this.SubKey = default (TKey);
 
79
 
 
80
                return this;
 
81
            }
 
82
        }
 
83
 
 
84
        class NodeObjectPool : ObjectPool<Node> {
 
85
            protected override Node Creator ()
 
86
            {
 
87
                return new Node ();
 
88
            }
 
89
        }
 
90
        static readonly NodeObjectPool pool = new NodeObjectPool ();
 
91
 
 
92
        const int MaxLoad = 5;
 
93
        const uint BucketSize = 512;
 
94
 
 
95
        Node head;
 
96
        Node tail;
 
97
 
 
98
        Node[] buckets = new Node [BucketSize];
 
99
        int count;
 
100
        int size = 2;
 
101
 
 
102
        SimpleRwLock slim = new SimpleRwLock ();
 
103
 
 
104
        readonly IEqualityComparer<TKey> comparer;
 
105
 
 
106
        public SplitOrderedList (IEqualityComparer<TKey> comparer)
 
107
        {
 
108
            this.comparer = comparer;
 
109
            head = new Node ().Init (0);
 
110
            tail = new Node ().Init (ulong.MaxValue);
 
111
            head.Next = tail;
 
112
            SetBucket (0, head);
 
113
        }
 
114
 
 
115
        public int Count {
 
116
            get {
 
117
                return count;
 
118
            }
 
119
        }
 
120
 
 
121
        public T InsertOrUpdate (uint key, TKey subKey, Func<T> addGetter, Func<T, T> updateGetter)
 
122
        {
 
123
            Node current;
 
124
            bool result = InsertInternal (key, subKey, default (T), addGetter, out current);
 
125
 
 
126
            if (result)
 
127
                return current.Data;
 
128
 
 
129
            // FIXME: this should have a CAS-like behavior
 
130
            return current.Data = updateGetter (current.Data);
 
131
        }
 
132
 
 
133
        public T InsertOrUpdate (uint key, TKey subKey, T addValue, T updateValue)
 
134
        {
 
135
            Node current;
 
136
            if (InsertInternal (key, subKey, addValue, null, out current))
 
137
                return current.Data;
 
138
 
 
139
            // FIXME: this should have a CAS-like behavior
 
140
            return current.Data = updateValue;
 
141
        }
 
142
        
 
143
        public bool Insert (uint key, TKey subKey, T data)
 
144
        {
 
145
            Node current;
 
146
            return InsertInternal (key, subKey, data, null, out current);
 
147
        }
 
148
 
 
149
        public T InsertOrGet (uint key, TKey subKey, T data, Func<T> dataCreator)
 
150
        {
 
151
            Node current;
 
152
            InsertInternal (key, subKey, data, dataCreator, out current);
 
153
            return current.Data;
 
154
        }
 
155
 
 
156
        bool InsertInternal (uint key, TKey subKey, T data, Func<T> dataCreator, out Node current)
 
157
        {
 
158
            Node node = pool.Take ().Init (ComputeRegularKey (key), subKey, data);
 
159
 
 
160
            uint b = key % (uint)size;
 
161
            Node bucket;
 
162
 
 
163
            if ((bucket = GetBucket (b)) == null)
 
164
                bucket = InitializeBucket (b);
 
165
 
 
166
            if (!ListInsert (node, bucket, out current, dataCreator))
 
167
                return false;
 
168
 
 
169
            int csize = size;
 
170
            if (Interlocked.Increment (ref count) / csize > MaxLoad && (csize & 0x40000000) == 0)
 
171
                Interlocked.CompareExchange (ref size, 2 * csize, csize);
 
172
 
 
173
            current = node;
 
174
 
 
175
            return true;
 
176
        }
 
177
        
 
178
        public bool Find (uint key, TKey subKey, out T data)
 
179
        {
 
180
            Node node;
 
181
            uint b = key % (uint)size;
 
182
            data = default (T);
 
183
            Node bucket;
 
184
 
 
185
            if ((bucket = GetBucket (b)) == null)
 
186
                bucket = InitializeBucket (b);
 
187
 
 
188
            if (!ListFind (ComputeRegularKey (key), subKey, bucket, out node))
 
189
                return false;
 
190
 
 
191
            data = node.Data;
 
192
 
 
193
            return !node.Marked;
 
194
        }
 
195
 
 
196
        public bool CompareExchange (uint key, TKey subKey, T data, Func<T, bool> check)
 
197
        {
 
198
            Node node;
 
199
            uint b = key % (uint)size;
 
200
            Node bucket;
 
201
 
 
202
            if ((bucket = GetBucket (b)) == null)
 
203
                bucket = InitializeBucket (b);
 
204
 
 
205
            if (!ListFind (ComputeRegularKey (key), subKey, bucket, out node))
 
206
                return false;
 
207
 
 
208
            if (!check (node.Data))
 
209
                return false;
 
210
 
 
211
            node.Data = data;
 
212
 
 
213
            return true;
 
214
        }
 
215
 
 
216
        public bool Delete (uint key, TKey subKey, out T data)
 
217
        {
 
218
            uint b = key % (uint)size;
 
219
            Node bucket;
 
220
 
 
221
            if ((bucket = GetBucket (b)) == null)
 
222
                bucket = InitializeBucket (b);
 
223
 
 
224
            if (!ListDelete (bucket, ComputeRegularKey (key), subKey, out data))
 
225
                return false;
 
226
 
 
227
            Interlocked.Decrement (ref count);
 
228
            return true;
 
229
        }
 
230
 
 
231
        public IEnumerator<T> GetEnumerator ()
 
232
        {
 
233
            Node node = head.Next;
 
234
 
 
235
            while (node != tail) {
 
236
                while (node.Marked || (node.Key & 1) == 0) {
 
237
                    node = node.Next;
 
238
                    if (node == tail)
 
239
                        yield break;
 
240
                }
 
241
                yield return node.Data;
 
242
                node = node.Next;
 
243
            }
 
244
        }
 
245
 
 
246
        Node InitializeBucket (uint b)
 
247
        {
 
248
            Node current;
 
249
            uint parent = GetParent (b);
 
250
            Node bucket;
 
251
 
 
252
            if ((bucket = GetBucket (parent)) == null)
 
253
                bucket = InitializeBucket (parent);
 
254
 
 
255
            Node dummy = pool.Take ().Init (ComputeDummyKey (b));
 
256
            if (!ListInsert (dummy, bucket, out current, null))
 
257
                return current;
 
258
 
 
259
            return SetBucket (b, dummy);
 
260
        }
 
261
        
 
262
        // Turn v's MSB off
 
263
        static uint GetParent (uint v)
 
264
        {
 
265
            uint t, tt;
 
266
            
 
267
            // Find MSB position in v
 
268
            var pos = (tt = v >> 16) > 0 ?
 
269
                (t = tt >> 8) > 0 ? 24 + logTable[t] : 16 + logTable[tt] :
 
270
                (t = v >> 8) > 0 ? 8 + logTable[t] : logTable[v];
 
271
 
 
272
            return (uint)(v & ~(1 << pos));
 
273
        }
 
274
 
 
275
        // Reverse integer bits and make sure LSB is set
 
276
        static ulong ComputeRegularKey (uint key)
 
277
        {
 
278
            return ComputeDummyKey (key) | 1;
 
279
        }
 
280
        
 
281
        // Reverse integer bits
 
282
        static ulong ComputeDummyKey (uint key)
 
283
        {
 
284
            return ((ulong)(((uint)reverseTable[key & 0xff] << 24) |
 
285
                            ((uint)reverseTable[(key >> 8) & 0xff] << 16) |
 
286
                            ((uint)reverseTable[(key >> 16) & 0xff] << 8) |
 
287
                            ((uint)reverseTable[(key >> 24) & 0xff]))) << 1;
 
288
        }
 
289
 
 
290
        // Bucket storage is abstracted in a simple two-layer tree to avoid too much memory resize
 
291
        Node GetBucket (uint index)
 
292
        {
 
293
            if (index >= buckets.Length)
 
294
                return null;
 
295
            return buckets[index];
 
296
        }
 
297
 
 
298
        Node SetBucket (uint index, Node node)
 
299
        {
 
300
            try {
 
301
                slim.EnterReadLock ();
 
302
                CheckSegment (index, true);
 
303
 
 
304
                Interlocked.CompareExchange (ref buckets[index], node, null);
 
305
                return buckets[index];
 
306
            } finally {
 
307
                slim.ExitReadLock ();
 
308
            }
 
309
        }
 
310
 
 
311
        // When we run out of space for bucket storage, we use a lock-based array resize
 
312
        void CheckSegment (uint segment, bool readLockTaken)
 
313
        {
 
314
            if (segment < buckets.Length)
 
315
                return;
 
316
 
 
317
            if (readLockTaken)
 
318
                slim.ExitReadLock ();
 
319
            try {
 
320
                slim.EnterWriteLock ();
 
321
                while (segment >= buckets.Length)
 
322
                    Array.Resize (ref buckets, buckets.Length * 2);
 
323
            } finally {
 
324
                slim.ExitWriteLock ();
 
325
            }
 
326
            if (readLockTaken)
 
327
                slim.EnterReadLock ();
 
328
        }
 
329
 
 
330
        Node ListSearch (ulong key, TKey subKey, ref Node left, Node h)
 
331
        {
 
332
            Node leftNodeNext = null, rightNode = null;
 
333
 
 
334
            do {
 
335
                Node t = h;
 
336
                Node tNext = t.Next;
 
337
                do {
 
338
                    if (!tNext.Marked) {
 
339
                        left = t;
 
340
                        leftNodeNext = tNext;
 
341
                    }
 
342
                    t = tNext.Marked ? tNext.Next : tNext;
 
343
                    if (t == tail)
 
344
                        break;
 
345
                    
 
346
                    tNext = t.Next;
 
347
                } while (tNext.Marked || t.Key < key || (tNext.Key == key && !comparer.Equals (subKey, t.SubKey)));
 
348
                
 
349
                rightNode = t;
 
350
                
 
351
                if (leftNodeNext == rightNode) {
 
352
                    if (rightNode != tail && rightNode.Next.Marked)
 
353
                        continue;
 
354
                    else 
 
355
                        return rightNode;
 
356
                }
 
357
                
 
358
                if (Interlocked.CompareExchange (ref left.Next, rightNode, leftNodeNext) == leftNodeNext) {
 
359
                    pool.Release (leftNodeNext);
 
360
                    if (rightNode != tail && rightNode.Next.Marked)
 
361
                        continue;
 
362
                    else
 
363
                        return rightNode;
 
364
                }
 
365
            } while (true);
 
366
        }
 
367
 
 
368
        bool ListDelete (Node startPoint, ulong key, TKey subKey, out T data)
 
369
        {
 
370
            Node rightNode = null, rightNodeNext = null, leftNode = null;
 
371
            data = default (T);
 
372
            Node markedNode = null;
 
373
            
 
374
            do {
 
375
                rightNode = ListSearch (key, subKey, ref leftNode, startPoint);
 
376
                if (rightNode == tail || rightNode.Key != key)
 
377
                    return false;
 
378
 
 
379
                data = rightNode.Data;
 
380
                rightNodeNext = rightNode.Next;
 
381
 
 
382
                if (!rightNodeNext.Marked) {
 
383
                    if (markedNode == null)
 
384
                        markedNode = pool.Take ();
 
385
                    markedNode.Init (rightNodeNext);
 
386
 
 
387
                    if (Interlocked.CompareExchange (ref rightNode.Next, markedNode, rightNodeNext) == rightNodeNext)
 
388
                        break;
 
389
                }
 
390
            } while (true);
 
391
            
 
392
            if (Interlocked.CompareExchange (ref leftNode.Next, rightNodeNext, rightNode) != rightNode)
 
393
                ListSearch (rightNode.Key, subKey, ref leftNode, startPoint);
 
394
            else
 
395
                pool.Release (rightNode);
 
396
            
 
397
            return true;
 
398
        }
 
399
        
 
400
        bool ListInsert (Node newNode, Node startPoint, out Node current, Func<T> dataCreator)
 
401
        {
 
402
            ulong key = newNode.Key;
 
403
            Node rightNode = null, leftNode = null;
 
404
            
 
405
            do {
 
406
                rightNode = current = ListSearch (key, newNode.SubKey, ref leftNode, startPoint);
 
407
                if (rightNode != tail && rightNode.Key == key && comparer.Equals (newNode.SubKey, rightNode.SubKey))
 
408
                    return false;
 
409
                
 
410
                newNode.Next = rightNode;
 
411
                if (dataCreator != null)
 
412
                    newNode.Data = dataCreator ();
 
413
                if (Interlocked.CompareExchange (ref leftNode.Next, newNode, rightNode) == rightNode)
 
414
                    return true;
 
415
            } while (true);
 
416
        }
 
417
        
 
418
        bool ListFind (ulong key, TKey subKey, Node startPoint, out Node data)
 
419
        {
 
420
            Node rightNode = null, leftNode = null;
 
421
            data = null;
 
422
            
 
423
            rightNode = ListSearch (key, subKey, ref leftNode, startPoint);
 
424
            data = rightNode;
 
425
            
 
426
            return rightNode != tail && rightNode.Key == key;
 
427
        }
 
428
 
 
429
        static readonly byte[] reverseTable = {
 
430
            0, 128, 64, 192, 32, 160, 96, 224, 16, 144, 80, 208, 48, 176, 112, 240, 8, 136, 72, 200, 40, 168, 104, 232, 24, 152, 88, 216, 56, 184, 120, 248, 4, 132, 68, 196, 36, 164, 100, 228, 20, 148, 84, 212, 52, 180, 116, 244, 12, 140, 76, 204, 44, 172, 108, 236, 28, 156, 92, 220, 60, 188, 124, 252, 2, 130, 66, 194, 34, 162, 98, 226, 18, 146, 82, 210, 50, 178, 114, 242, 10, 138, 74, 202, 42, 170, 106, 234, 26, 154, 90, 218, 58, 186, 122, 250, 6, 134, 70, 198, 38, 166, 102, 230, 22, 150, 86, 214, 54, 182, 118, 246, 14, 142, 78, 206, 46, 174, 110, 238, 30, 158, 94, 222, 62, 190, 126, 254, 1, 129, 65, 193, 33, 161, 97, 225, 17, 145, 81, 209, 49, 177, 113, 241, 9, 137, 73, 201, 41, 169, 105, 233, 25, 153, 89, 217, 57, 185, 121, 249, 5, 133, 69, 197, 37, 165, 101, 229, 21, 149, 85, 213, 53, 181, 117, 245, 13, 141, 77, 205, 45, 173, 109, 237, 29, 157, 93, 221, 61, 189, 125, 253, 3, 131, 67, 195, 35, 163, 99, 227, 19, 147, 83, 211, 51, 179, 115, 243, 11, 139, 75, 203, 43, 171, 107, 235, 27, 155, 91, 219, 59, 187, 123, 251, 7, 135, 71, 199, 39, 167, 103, 231, 23, 151, 87, 215, 55, 183, 119, 247, 15, 143, 79, 207, 47, 175, 111, 239, 31, 159, 95, 223, 63, 191, 127, 255
 
431
        };
 
432
 
 
433
        static readonly byte[] logTable = {
 
434
            0xFF, 0, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
 
435
        };
 
436
 
 
437
        struct SimpleRwLock
 
438
        {
 
439
            const int RwWait = 1;
 
440
            const int RwWrite = 2;
 
441
            const int RwRead = 4;
 
442
 
 
443
            int rwlock;
 
444
 
 
445
            public void EnterReadLock ()
 
446
            {
 
447
                SpinWait sw = new SpinWait ();
 
448
                do {
 
449
                    while ((rwlock & (RwWrite | RwWait)) > 0)
 
450
                        sw.SpinOnce ();
 
451
 
 
452
                    if ((Interlocked.Add (ref rwlock, RwRead) & (RwWait | RwWait)) == 0)
 
453
                        return;
 
454
 
 
455
                    Interlocked.Add (ref rwlock, -RwRead);
 
456
                } while (true);
 
457
            }
 
458
 
 
459
            public void ExitReadLock ()
 
460
            {
 
461
                Interlocked.Add (ref rwlock, -RwRead);
 
462
            }
 
463
 
 
464
            public void EnterWriteLock ()
 
465
            {
 
466
                SpinWait sw = new SpinWait ();
 
467
                do {
 
468
                    int state = rwlock;
 
469
                    if (state < RwWrite) {
 
470
                        if (Interlocked.CompareExchange (ref rwlock, RwWrite, state) == state)
 
471
                            return;
 
472
                        state = rwlock;
 
473
                    }
 
474
                    // We register our interest in taking the Write lock (if upgradeable it's already done)
 
475
                    while ((state & RwWait) == 0 && Interlocked.CompareExchange (ref rwlock, state | RwWait, state) != state)
 
476
                        state = rwlock;
 
477
                    // Before falling to sleep
 
478
                    while (rwlock > RwWait)
 
479
                        sw.SpinOnce ();
 
480
                } while (true);
 
481
            }
 
482
 
 
483
            public void ExitWriteLock ()
 
484
            {
 
485
                Interlocked.Add (ref rwlock, -RwWrite);
 
486
            }
 
487
        }
 
488
    }
 
489
 
 
490
#if !NET_4_0
 
491
    internal struct SpinWait
 
492
    {
 
493
        // The number of step until SpinOnce yield on multicore machine
 
494
        const           int  step = 10;
 
495
        const           int  maxTime = 200;
 
496
        static readonly bool isSingleCpu = (Environment.ProcessorCount == 1);
 
497
 
 
498
        int ntime;
 
499
 
 
500
        public void SpinOnce ()
 
501
        {
 
502
            ntime += 1;
 
503
 
 
504
            if (isSingleCpu) {
 
505
                // On a single-CPU system, spinning does no good
 
506
                Thread.Sleep (0);
 
507
            } else {
 
508
                if (ntime % step == 0)
 
509
                    Thread.Sleep (0);
 
510
                else
 
511
                    // Multi-CPU system might be hyper-threaded, let other thread run
 
512
                    Thread.SpinWait (Math.Min (ntime, maxTime) << 1);
 
513
            }
 
514
        }
 
515
    }
 
516
#endif
 
517
}
 
518
 
 
519
#endif
 
 
b'\\ No newline at end of file'