1. 程式人生 > >C#開源磁碟/記憶體快取引擎

C#開源磁碟/記憶體快取引擎

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using STSdb4.Database;
using fastJSON;
using System.IO;

namespace Com.SuperCache.Engine
{
    public class RawCache : BaseCache
    {
        private const string ExpirationFileExtension = "exp";
        private const string DataFileExtension = "dat";
        private const string statFile = "SuperCache.sta";
        private string dataPath;
        private static Dictionary<string, object> memoryData = new Dictionary<string, object>();
        private static Dictionary<string, DateTime?> memoryExpiration = new Dictionary<string, DateTime?>();
        private static object syncRoot = new object();
        private bool isMemory = false;
        private RecycleAlgorithms recycleAlgorithm;
        private int maxCount;
        private int threshold;
        private static Dictionary<string, KeyValue> usageStat = new Dictionary<string, KeyValue>();
        private Dictionary<string, KeyValuePair<DateTime, string>> expiredFiles = new Dictionary<string, KeyValuePair<DateTime, string>>();
        private RecycleModes recycleMode;

        public RawCache(string DataPath, RecycleAlgorithms RecycleAlgorithm, int MaxCount, int Threshold, RecycleModes RecycleMode)
        {
            dataPath = DataPath;
            if (!dataPath.EndsWith(Path.DirectorySeparatorChar.ToString()))
                dataPath += Path.DirectorySeparatorChar;

            isMemory = string.IsNullOrEmpty(DataPath);

            recycleAlgorithm = RecycleAlgorithm;
            maxCount = MaxCount;
            threshold = Threshold;
            recycleMode = RecycleMode;
        }

        public override void Add<K>(string Category, K Key, object Data)
        {
            Add(Category, Key, Data, null);
        }

        private string GetExpirationTable(string Category)
        {
            return KeyExpiration + "_" + Category;
        }

        public override void Add<K, V>(string Category, IEnumerable<KeyValuePair<K, V>> Items, DateTime? ExpirationDate)
        {
            long count = 0;

            lock (syncRoot)
            {
                Items.ForEach(i =>
                    {
                        var key = i.Key;
                        var data = i.Value;
                        var cacheKey = GetKey(Category, key.ToString());

                        if (isMemory)
                        {
                            memoryData[cacheKey] = data;
                            memoryExpiration[cacheKey] = ExpirationDate;

                            //recycle algo
                            switch (recycleAlgorithm)
                            {
                                case RecycleAlgorithms.MRU:
                                    usageStat[cacheKey] = new KeyValue(string.Empty, 0);
                                    if (recycleMode == RecycleModes.Active)
                                        Recycle<K>(Category, memoryData.Count);
                                    break;
                                default:
                                    break;
                            }
                        }
                        else
                        {
                            //will only serialize object other than string
                            var result = typeof(V) == typeof(string) ? data as string : JSON.Instance.ToJSON(data);
                            var fileKey = key.ToString();
                            var dataFile = GetFile(Category, fileKey, true);
                            bool exists = File.Exists(dataFile);
                            File.WriteAllText(dataFile, result);

                            //specify expiration
                            //default 30 mins to expire from now
                            var expirationDate = ExpirationDate == null || ExpirationDate <= DateTime.Now ? DateTime.Now.AddMinutes(30) : (DateTime)ExpirationDate;
                            var expirationFile = GetFile(Category, fileKey, false);
                            File.WriteAllText(expirationFile, expirationDate.ToString());

                            //recycle algo
                            if (recycleAlgorithm != RecycleAlgorithms.None)
                            {
                                var statFilePath = dataPath + statFile;
                                if (File.Exists(statFilePath))
                                {
                                    var buffer = File.ReadAllText(statFilePath);
                                    count = Convert.ToInt32(buffer);
                                }
                                if (!exists)
                                {
                                    count++;
                                    File.WriteAllText(statFilePath, count.ToString());
                                }
                                switch (recycleAlgorithm)
                                {
                                    case RecycleAlgorithms.MRU:
                                        usageStat[cacheKey] = new KeyValue(expirationFile, 0);
                                        expiredFiles[cacheKey] = new KeyValuePair<DateTime, string>(expirationDate, expirationFile);
                                        if (recycleMode == RecycleModes.Active)
                                            Recycle<K>(Category, count);
                                        break;
                                    default:
                                        break;
                                }
                            }
                        }
                    });

                if (recycleAlgorithm != RecycleAlgorithms.None && recycleMode == RecycleModes.Passive)
                {
                    if (isMemory)
                        count = memoryData.Count;
                    Recycle<K>(Category, count);
                }
            }
        }

        public override void Add<K>(string Category, K Key, object Data, DateTime? ExpirationDate)
        {
            Add<K, object>(Category, new List<KeyValuePair<K, object>> { new KeyValuePair<K, object>(Key, Data) }, ExpirationDate);
        }

        private string GetFile(string Category, string FileName, bool IsData)
        {
            var path = dataPath + Category.NormalizeFileName() + @"\";
            if (!Directory.Exists(path))
                Directory.CreateDirectory(path);
            return path + FileName.NormalizeFileName() + "." + (IsData ? "dat" : ExpirationFileExtension);
        }

        private string GetKey(string Category, string Key)
        {
            return Category + "_" + Key;
        }

        public override List<KeyValuePair<K, V>> Get<K, V>(string Category, IEnumerable<K> Keys)
        {
            var result = new List<KeyValuePair<K, V>>();
            lock (syncRoot)
            {
                Keys.ForEach(key =>
                    {
                        string buffer;
                        V value;
                        var cacheKey = GetKey(Category, key.ToString());
                        if (isMemory)
                        {
                            object memBuffer;
                            if (memoryData.TryGetValue(cacheKey, out memBuffer))
                            {
                                //track recycle
                                switch (recycleAlgorithm)
                                {
                                    case RecycleAlgorithms.MRU:
                                        usageStat[cacheKey].Value++;
                                        break;
                                    default:
                                        break;
                                }

                                value = (V)memBuffer;
                                DateTime? expirationDate;
                                if (memoryExpiration.TryGetValue(cacheKey, out expirationDate))
                                {
                                    //expired
                                    if (expirationDate != null && (DateTime)expirationDate < DateTime.Now)
                                    {
                                        value = default(V);
                                        memoryData.Remove(cacheKey);
                                        memoryExpiration.Remove(cacheKey);
                                    }
                                }
                            }
                            else
                                value = default(V);
                        }
                        else
                        {
                            var dataFilePath = GetFile(Category, key.ToString(), true);
                            if (File.Exists(dataFilePath))
                            {
                                buffer = File.ReadAllText(dataFilePath);

                                //track recycle
                                switch (recycleAlgorithm)
                                {
                                    case RecycleAlgorithms.MRU:
                                        usageStat[cacheKey].Value++;
                                        break;
                                    default:
                                        break;
                                }

                                //will only deserialize object other than string
                                value = typeof(V) == typeof(string) ? (V)(object)buffer : JSON.Instance.ToObject<V>(buffer);
                                DateTime expirationDate;
                                var expirationFilePath = GetFile(Category, key.ToString(), false);
                                if (File.Exists(expirationFilePath))
                                {
                                    buffer = File.ReadAllText(expirationFilePath);
                                    expirationDate = Convert.ToDateTime(buffer);
                                    //expired
                                    if (expirationDate < DateTime.Now)
                                    {
                                        value = default(V);
                                        File.Delete(dataFilePath);
                                        File.Delete(expirationFilePath);
                                    }
                                }
                            }
                            else
                                value = default(V);
                        }

                        result.Add(new KeyValuePair<K, V>(key, value));
                    });
            }
            return result;
        }

        public override V Get<K, V>(string Category, K Key)
        {
            var buffer = Get<K, V>(Category, new K[] { Key });
            var result = buffer.FirstOrDefault();
            return result.Value;
        }

        public override void Recycle<K>(string Category, long Count)
        {
            if (Count < maxCount)
                return;

            switch (recycleAlgorithm)
            {
                case RecycleAlgorithms.MRU:
                    lock (syncRoot)
                    {
                        var recycledFileCount = 0;

                        if (isMemory)
                        {
                            //find out expired items
                            var memExpired = memoryExpiration.Where(e => e.Value != null && (DateTime)e.Value < DateTime.Now);
                            memExpired.ForEach(u =>
                            {
                                memoryData.Remove(u.Key);
                                memoryExpiration.Remove(u.Key);
                                usageStat.Remove(u.Key);
                            });
                        }
                        else
                        {
                            if (expiredFiles.Count == 0)
                            {
                                Directory.GetFiles(dataPath, "*." + ExpirationFileExtension).ForEach(f =>
                                    {
                                        var buffer = File.ReadAllText(f);
                                        var expirationDate = Convert.ToDateTime(buffer);
                                        expiredFiles[Path.GetFileNameWithoutExtension(f)] = new KeyValuePair<DateTime, string>(expirationDate, f);
                                    });
                            }
                            //find out expired items
                            var fileExpired = expiredFiles.Where(e => e.Value.Key < DateTime.Now);
                            fileExpired.ForEach(u =>
                            {
                                var dataFile = Path.ChangeExtension(u.Value.Value, DataFileExtension);
                                File.Delete(dataFile);
                                File.Delete(u.Value.Value);
                                usageStat.Remove(u.Key);
                                recycledFileCount++;
                            });
                        }

                        //find out least used items
                        var leastUsed = usageStat.OrderByDescending(s => s.Value.Value).Skip(maxCount - threshold);
                        leastUsed.ForEach(u =>
                            {
                                if (isMemory)
                                {
                                    memoryData.Remove(u.Key);
                                    memoryExpiration.Remove(u.Key);
                                }
                                else
                                {
                                    var dataFile = Path.ChangeExtension(u.Value.Key, DataFileExtension);
                                    if (File.Exists(dataFile))
                                    {
                                        recycledFileCount++;
                                        File.Delete(dataFile);
                                    }
                                    if (File.Exists(u.Value.Key))
                                        File.Delete(u.Value.Key);
                                }
                                usageStat.Remove(u.Key);
                            });

                        if (!isMemory)
                        {
                            var statFilePath = dataPath + statFile;
                            var count = 0;
                            if (File.Exists(statFilePath))
                            {
                                var buffer = File.ReadAllText(statFilePath);
                                count = Convert.ToInt32(buffer);
                            }
                            count = count - recycledFileCount;
                            if (count < 0)
                                count = 0;
                            File.WriteAllText(statFilePath, count.ToString());
                        }
                    }
                    break;
                default:
                    break;
            }
        }
    }
}

相關推薦

C#開源磁碟/記憶體快取引擎

using System; using System.Collections.Generic; using System.Linq; using System.Text; using STSdb4.Database; using fastJSON; using System.IO; na

Android RxJava 實戰系列:從磁碟 / 記憶體快取中 獲取快取資料

前言 Rxjava,由於其基於事件流的鏈式呼叫、邏輯簡潔 & 使用簡單的特點,深受各大 Android開發者的歡迎。 RxJava如此受歡迎的原因,在於其提供了豐富 &

Fresco磁碟記憶體快取 工具類

1. 新增依賴,在AndroidManifest.xml清單檔案中配置: compile 'com.facebook.fresco:fresco:1.5.0' <application android:name=".util.BaseApplication"  

基於STSdb和fastJson的磁碟/記憶體快取

更新 1. 增加了對批量處理的支援,寫操作速度提升5倍,讀操作提升100倍 2. 增加了對併發的支援 需求 業務系統用的是資料庫,資料量大,部分只讀或相對穩定業務查詢複雜,每次頁面載入都要花耗不少時間(不討論非同步),覺得可以做一下快取記憶體,譬如用nosql那種key/value快速存取結果 目的

Xenko C#開源遊戲引擎入門

on() actor scale con 為什麽 pro and 三維 str 最近使有和 Three.js 開發三維頁面,覺得很有趣。以前在做WP應用的時候使用過MonoGame做過一點東西,後來Windows 10上來,MonoGame好像不怎麽支持了,也沒

Android RxJava操作符的學習---組合合併操作符---從磁碟記憶體快取中獲取快取資料

1. 需求場景     2. 功能說明 對於從磁碟 / 記憶體快取中 獲取快取資料 的功能邏輯如下: 3. 具體實現 詳細請看程式碼註釋 // 該2變數用於模擬記憶體快取 & 磁碟快取中的資料 String me

高併發、低延遲之C#玩轉CPU快取記憶體(附示例)

寫在前面 好久沒有寫部落格了,一直在不斷地探索響應式DDD,又get到了很多新知識,解惑了很多老問題,最近讀了Martin Fowler大師一篇非常精彩的部落格The LMAX Architecture,裡面有一個術語Mechanical Sympathy,姑且翻譯成軟硬體協同程式設計(Hardware an

.NET高效能程式設計之C#玩轉CPU快取記憶體(附示例)

寫在前面 好久沒有寫部落格了,一直在不斷地探索響應式DDD,又get到了很多新知識,解惑了很多老問題,最近讀了Martin Fowler大師一篇非常精彩的部落格The LMAX Architecture,裡面有一個術語Mechanical Sympathy,姑且翻譯成軟硬體協同程式設計(Hardware a

H2:開源記憶體資料庫引擎

本資源由  伯樂線上 -  劉立華 整理 H2是一個開源的記憶體資料庫。Java編寫、快速、小巧(1.5MB jar包)還提供了Web控制檯管理資料庫內容。 主要功能 非常快速的資料庫引擎。 開源。 Java編寫。 支援標準SQL、

磁碟快取記憶體快取的區別

記憶體快取 快取記憶體(英語:cache,英語發音:/kæʃ/ kash [1][2][3],簡稱快取),其原始意義是指訪問速度比一般隨機存取儲存器(RAM)快的一種RAM,通常它不像系統主存那樣使用DRAM技術,而使用昂貴但較快速的SRAM技術。 原理

Glide 快取策略 記憶體快取磁碟快取

本文主要介紹瞭如何配置和管理Glide中的快取,其中大部分內容都可以直接在官方Wiki中找到,這裡只是進行了整理和彙總。言歸正傳,Glide支援圖片的二級快取(並不是三級快取,因為從網路載入並不屬於快取),即記憶體快取和磁碟快取。 磁碟快取 一般的圖片快取指的就是磁碟快取

Glide原始碼閱讀(四)記憶體快取磁碟快取、跳過快取

一、記憶體快取實現com.bumptech.glide.util.LruCache<T, Y>中,通過LinkedHashMap做記憶體快取Engine中,MemoryCache.put(EngineKey, EngineResource);新增到LinkedHa

Glide 快取工具例子,快取大小獲取,磁碟快取清除(2 種方法),記憶體快取清除

Glide 快取 Simple快取路徑的指定快取大小的獲取磁碟快取清除(兩種方法)記憶體快取清除可 clone 之後檢視使用 SimpleGlide cache Simple.The cache path specifiedThe cache sizeThe disk cache (two ways)Memo

CPU記憶體磁碟快取關係?(加深理解)

1. 暫存器是中央處理器內的組成部份。暫存器是有限存貯容量的高速存貯部件,它們可用來暫存指令、資料和位址。在中央處理器的控制部件中,包含的暫存器有指令暫存器(IR)和程式計數器(PC)。在中央處理器的算術及邏輯部件中,包含的暫存器有累加器(ACC)。 2. 記

Android快取機制Lrucache記憶體快取和DiskLruCache磁碟快取

1.1 記憶體快取——LruCache原始碼分析     1.1.1 LRU     LRU,全稱Least Rencetly Used,即最近最少使用,是一種非常常用的置換演算法,也即淘汰最長時間未使用的物件。LRU在作業系統中的頁面置換演算法中廣泛使用,我們的記憶體或快取空間是有限的,當新加入一個物

iOS開發之記憶體快取 磁碟快取 沙盒

        最近一直看到“快取”兩字,索性自己總結一下,希望大神看到多多指點。         說到快取,快取分為記憶體快取和磁碟快取兩種,記憶體是指當前程式的執行空間,磁碟是程式的儲存空間; 記憶體快取速度快容量小,磁碟快取容量大速度慢可持久化;記憶體是臨時儲存檔案用

Android記憶體快取磁碟快取的實現

記憶體快取 Android自帶的LruCache實現了記憶體快取,LruCache內部主要使用LinkedHashMap的特性來實現,因為LinkedHashMap可支援FIFO和LRU訪問。 LinkedHashMap的特點 LinkedHashMap繼

站在巨人的肩膀上,C++開源庫大全

windows應用 pcr ram perl t對象 rest 容器 企業應用 聲音 程序員要站在巨人的肩膀上,C++擁有豐富的開源庫,這裏包括:標準庫、Web應用框架、人工智能、數據庫、圖片處理、機器學習、日誌、代碼分析等。 標準庫 C++ Standard

Linux下經常使用的C/C++開源Socket庫

bsd 面向對象 sql數據庫 高速 com telnet ade ftp 版本 1. Linux Socket Programming In C++ : http://tldp.org/LDP/LG/issue74/tougher.html2. A

c#開源工具(或者C# 開源框架)

stack windows 框架 ado doc 2.0 release dal .com 1.轉載聲明:本篇內容轉載自http://www.cnblogs.com/gaoyuchuanIT/articles/5612268.html。 2. C# 開源框架(整理)