📄 blobcache.h
字号:
#pragma once
#include <atlrx.h>
#include <string>
#include <fstream>
namespace VCUE
{
HRESULT GetLineFromFile(const CStringA& strFile, const unsigned int nLine, std::string& strLine)
{
HRESULT hr = E_FAIL;
std::ifstream fsFile;
fsFile.open(strFile);
if (fsFile.is_open())
{
hr = S_OK;
for (unsigned int nCurrentLine = 0; nCurrentLine < nLine; ++nCurrentLine)
{
if (fsFile.eof() || !fsFile.good())
return E_FAIL;
std::getline(fsFile, strLine);
}
}
return hr;
}
} // namespace VCUE
const int CACHE_SIZE_LIMIT = 5;
[ request_handler("Default") ]
class CBlobCacheHandler
{
public:
HTTP_CODE ValidateAndExchange()
{
HRESULT hr = E_UNEXPECTED;
//从isapi扩展中获得服务
hr = QueryService(&m_spCache);
if (FAILED(hr))
return SendError("未能获得内存缓存");
hr = QueryService(&m_spCacheControl);
if (FAILED(hr))
return SendError("未能获得内存缓存控制");
hr = QueryService(&m_spCacheStats);
if (FAILED(hr))
return SendError("未能获得内存缓存统计对象");
hr = QueryService(&m_spCacheClient);
if (FAILED(hr))
return SendError("未能获得内存缓存客户服务");
hr = m_spCacheControl->SetMaxAllowedEntries( CACHE_SIZE_LIMIT );
if (FAILED(hr))
return SendError("未能设置缓存中的最大入口数目");
hr = m_HttpResponse.SetContentType("text/html");
const CHttpRequestParams& formFields = m_HttpRequest.GetFormVars();
//点击了"Clearcache"提交
if (formFields.Lookup("Clearcache"))
{
hr = m_spCacheControl->ResetCache();
if (SUCCEEDED(hr))
{
strStatus = "成功清除了缓存";
return HTTP_SUCCESS;
}
else
return SendError("清除缓存失败");
}
//点"Clear State"提交
if (formFields.Lookup("Clearstats"))
{
hr = m_spCacheStats->ClearStats();
if (SUCCEEDED(hr))
{
strStatus = "成功清除了统计对象";
return HTTP_SUCCESS;
}
else
return SendError("清除统计失败");
}
//获得输入的查询
CStringA strKey = formFields.Lookup("keystr");
strKey.Trim();
// 获取字符串长度
if (0 == strKey.GetLength())
{
strStatus = "没有输入键。请输入1到100之间的数字";
return HTTP_SUCCESS;
}
// 正则表达式验证
CAtlRegExp<CAtlRECharTraitsA> regularExpression;
if (REPARSE_ERROR_OK != regularExpression.Parse("^[1-9][0-9]?0?$"))
return SendError("初始化正则表达式失败");
CAtlREMatchContext<CAtlRECharTraitsA> matchContext;
if (!regularExpression.Match(strKey, &matchContext))
{
strStatus = "无效的键请输入1到100的数值";
return HTTP_SUCCESS;
}
//从缓冲中获得数据
HCACHEITEM hEntry = 0;
//获得入口
hr=m_spCache->LookupEntry(strKey, &hEntry );
if (SUCCEEDED(hr))
{
DWORD dwSize = 0;
LPSTR szData = 0;
//获得数据
hr=m_spCache->GetData(hEntry, reinterpret_cast<void**>(&szData),&dwSize );
if (SUCCEEDED(hr))
{
// 复制数据
strData = szData;
strStatus = "从缓冲中取得了数据";
}
else
return SendError("从缓冲中获取数据失败");
}
else//从文件加载数据
{
strStatus = "没有在缓存中发现数据";
CStringA strDataFile;
if (!m_HttpRequest.GetPhysicalPath(strDataFile))
return SendError("未能获得物理路径");
strDataFile += "values.txt";
std::string strValue;
hr = VCUE::GetLineFromFile(strDataFile, atoi(strKey), strValue);
if (FAILED(hr))
return SendError("未能从文件中读取数据");
strData = strValue.c_str();
//分配内存
DWORD dwSize = strData.GetLength() + 1;
LPSTR szValue = static_cast<LPSTR>(::HeapAlloc(::GetProcessHeap(), 0, dwSize));
if (!CopyCString(strData, szValue, &dwSize))
return SendError("未能拷贝字符串");
FILETIME ft = {0};
//加入到缓冲区
//m_spCacheClient指定删除缓冲区的操作
hr = m_spCache->Add(strKey, szValue, dwSize, &ft, 0, 0, m_spCacheClient);
if (FAILED(hr))
return SendError("未能将值加入到缓冲区");
}
m_spCache->Flush();
return HTTP_SUCCESS;
}
protected:
[ tag_name(name="limit") ]
HTTP_CODE OnLimit(void)
{
HRESULT hr = E_UNEXPECTED;
DWORD dwMaximumAllowedEntries = 0;
hr = m_spCacheControl->GetMaxAllowedEntries(&dwMaximumAllowedEntries);
if (FAILED(hr))
return SendError("未能获得最大的入口数");
DWORD dwMaximumAllowedSize = 0;
hr = m_spCacheControl->GetMaxAllowedSize(&dwMaximumAllowedSize);
if (FAILED(hr))
return SendError("未能获得最大大小");
m_HttpResponse << "<p>缓冲中允许的最大入口数为: " << dwMaximumAllowedEntries << "</p>";
m_HttpResponse << "<p>缓存允许的最大大小为:" << dwMaximumAllowedSize << "</p>";
return HTTP_SUCCESS;
}
[ tag_name(name="output") ]
HTTP_CODE OnOutput(void)
{
m_HttpResponse << "<tr><td><b>值</b></td><td>\"" << strData << "\"</td></tr>";
m_HttpResponse << "<tr><td><b>状态</b></td><td>" << strStatus << "</td></tr>";
return HTTP_SUCCESS;
}
[ tag_name(name="stats") ]
HTTP_CODE OnStats(void)
{
HRESULT hr = E_UNEXPECTED;
DWORD dwHits = 0;
hr = m_spCacheStats->GetHitCount(&dwHits);
if (FAILED(hr))
return SendError("未能获得点击数");
DWORD dwMisses = 0;
m_spCacheStats->GetMissCount(&dwMisses);
if (FAILED(hr))
return SendError("未能获得未命中数");
DWORD dwMaximumEntries = 0;
m_spCacheStats->GetMaxEntryCount(&dwMaximumEntries);
if (FAILED(hr))
return SendError("未能获得最大入口项数");
DWORD dwCurrentEntries = 0;
m_spCacheStats->GetCurrentEntryCount(&dwCurrentEntries);
if (FAILED(hr))
return SendError("未能获得当前入口数");
DWORD dwMaximumSize = 0;
m_spCacheStats->GetMaxAllocSize(&dwMaximumSize);
if (FAILED(hr))
return SendError("未能获得缓存项的最大大小");
DWORD dwCurrentSize = 0;
m_spCacheStats->GetCurrentAllocSize(&dwCurrentSize);
if (FAILED(hr))
return SendError("未能获得当前缓存项的大小");
m_HttpResponse << "<tr><td><b>击中</b></td><td>" << dwHits << "</td></tr>";
m_HttpResponse << "<tr><td><b>丢失</b></td><td>" << dwMisses << "</td></tr>";
m_HttpResponse << "<tr><td><b>当前入口</b></td><td>" << dwCurrentEntries << "</td></tr>";
m_HttpResponse << "<tr><td><b>当前大小</b></td><td>" << dwCurrentSize << "</td></tr>";
m_HttpResponse << "<tr><td><b>最大入口</b></td><td>" << dwMaximumEntries << "</td></tr>";
m_HttpResponse << "<tr><td><b>最大大小</b></td><td>" << dwMaximumSize << "</td></tr>";
return HTTP_SUCCESS;
}
private:
// 帮助类
template <class ComInterface>
HRESULT QueryService(ComInterface** ppInterface)
{
return m_spServiceProvider->QueryService(__uuidof(ComInterface), ppInterface);
}
// 显示错误消息
HTTP_CODE SendError(const CStringA& strError, WORD wHttpStatus = 500)
{
// 清除缓冲区中响应
m_HttpResponse.ClearResponse();
// 不缓存
m_HttpResponse.SetCacheControl("no-cache");
m_HttpResponse.SetExpires(0);
// 设置状态代码
m_HttpResponse.SetStatusCode(wHttpStatus);
// 创建响应
m_HttpResponse << "<html><head><title>BlobCache 错误</title></head><body><p>" << strError << "</p></body></html>";
// 返回HTTP_CODE
return AtlsHttpError(wHttpStatus, SUBERR_NO_PROCESS);
}
// 数据成员
CComPtr<IMemoryCache> m_spCache;
CComPtr<IMemoryCacheControl> m_spCacheControl;
CComPtr<IMemoryCacheStats> m_spCacheStats;
CComPtr<IMemoryCacheClient> m_spCacheClient;
CStringA strData;
CStringA strStatus;
};
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -