Example #1
0
        private void sweepCacheRec(DateTime now, CacheRec rec)
        {
            var age = 0;
            var cd  = rec.m_CreateDate;

            if (cd.Ticks != 0)
            {
                age          = (int)(now - cd).TotalSeconds;
                rec.m_AgeSec = age;     // the Age field is needed for efficency not to compute dates on Table.Get()
            }
            else
            {
                rec.m_CreateDate = now;
                return;
            }

            var rma = rec.m_MaxAgeSec;
            var axp = rec.m_AbsoluteExpirationUTC;

            if (
                (age > (rma > 0 ? rma : this.m_MaxAgeSec)) ||
                (axp.HasValue && now > axp.Value)
                )
            {
                this.Remove(rec.Key);   //delete expired
                Interlocked.Increment(ref stat_SweepRemoveCount);
            }
        }
Example #2
0
 /// <summary>
 /// Puts a key-identified item into this table.
 /// If item with such key is already in this table then replaces it and returns false, returns true otherwise
 /// </summary>
 /// <param name="key">Item's unique key</param>
 /// <param name="value">Item</param>
 /// <param name="rec">Returns new or existing CacheRec</param>
 /// <param name="maxAgeSec">For how long will the item exist in cache before it gets swept out. Pass 0 to use table-level setting (default)</param>
 /// <param name="priority">Items priority relative to others in the table used during collision resolution, 0 = default</param>
 /// <param name="absoluteExpirationUTC">Sets absolute UTC time stamp when item should be swept out of cache, null is default</param>
 public bool Put(ulong key, object value, out CacheRec rec, int maxAgeSec = 0, int priority = 0, DateTime?absoluteExpirationUTC = null)
 {
     Interlocked.Increment(ref stat_PutCount);
     return(_Put(key, value, out rec, maxAgeSec, priority, absoluteExpirationUTC));
 }
Example #3
0
        private bool _Put(ulong key, object value, out CacheRec rec, int maxAgeSec, int priority, DateTime?absoluteExpirationUTC)
        {
            if (value == null)
            {
                throw new NFXException(StringConsts.ARGUMENT_ERROR + "Cache.TablePut(item=null)");
            }

            var idx = getBucketIndex(key);

            var lck = m_Locks[getLockIndex(idx)];

            lock (lck)
            {
                var bucketed = m_Buckets[idx];

                if (bucketed == null)
                {
                    rec            = new CacheRec(key, value, maxAgeSec, priority, absoluteExpirationUTC);
                    m_Buckets[idx] = rec;
                    Interlocked.Increment(ref m_Count);
                    Interlocked.Increment(ref stat_PutInsertCount);
                    return(true);
                }
                else
                {
                    if (bucketed is Page)
                    {
                        var page = (Page)bucketed;

                        lock (page)
                        {
                            var pidx = getPageIndex(key);

                            var existing = page.m_Records[pidx];
                            if (existing != null)
                            {
                                if (existing.Key == key)   //reuse the CacheRec instance
                                {
                                    existing.ReuseCTOR(value, maxAgeSec, priority, absoluteExpirationUTC);
                                    Interlocked.Increment(ref stat_PutReplaceCount);
                                    rec = existing;
                                    return(false);
                                }

                                if (existing.m_Priority <= priority)
                                {
                                    rec = new CacheRec(key, value, maxAgeSec, priority, absoluteExpirationUTC);
                                    page.m_Records[pidx] = rec;
                                    Interlocked.Increment(ref stat_PutCollisionCount);
                                    return(false);
                                }
                                rec = existing;
                                Interlocked.Increment(ref stat_PutPriorityPreventedCollisionCount);
                                return(false);
                            }
                            rec = new CacheRec(key, value, maxAgeSec, priority, absoluteExpirationUTC);
                            page.m_Records[pidx] = rec;
                            Interlocked.Increment(ref stat_PutInsertCount);
                        }
                        Interlocked.Increment(ref m_Count);
                        return(true);
                    }
                    else
                    {
                        var existing = (CacheRec)bucketed;
                        if (existing.Key == key)
                        {
                            existing.ReuseCTOR(value, maxAgeSec, priority, absoluteExpirationUTC);
                            rec = existing;
                            Interlocked.Increment(ref stat_PutReplaceCount);
                            return(false);
                        }
                        else
                        {    //1st collision
                            var pidx  = getPageIndex(existing.Key);
                            var npidx = getPageIndex(key);

                            if (npidx == pidx)  //collision
                            {
                                if (existing.m_Priority <= priority)
                                {
                                    rec            = new CacheRec(key, value, maxAgeSec, priority, absoluteExpirationUTC);
                                    m_Buckets[idx] = rec;
                                    Interlocked.Increment(ref stat_PutCollisionCount);
                                    return(false);
                                }

                                rec = existing;
                                Interlocked.Increment(ref stat_PutPriorityPreventedCollisionCount);
                                return(false);
                            }

                            // turn CacheRec into a Page
                            var page = new Page(m_RecPerPage);
                            Interlocked.Increment(ref stat_PutPageCreateCount);
                            Interlocked.Increment(ref m_PageCount);
                            page.m_Records[pidx] = existing;

                            rec = new CacheRec(key, value, maxAgeSec, priority, absoluteExpirationUTC);
                            page.m_Records[npidx] = rec;
                            Thread.MemoryBarrier();
                            m_Buckets[idx] = page;    //assign page to backet AFTER page init above

                            Interlocked.Increment(ref m_Count);
                            Interlocked.Increment(ref stat_PutInsertCount);
                            return(true);
                        }
                    }
                }
            }    //lock
        }
Example #4
0
 internal Page(int recPerPage)
 {
     m_Records = new CacheRec[recPerPage];
 }