基礎:html
GE的核心是一個處理原始二進制文件的鍵值存儲。您能夠將一個二進制數保存到由指定的鍵標識的GE鍵-值存儲中,而後將其加載回程序中。密鑰是64位整數;而引用GE數據對象(或GE術語中的單元格)的惟一本地方法就是經過這樣一個鍵。可是,其餘類型的鍵(如字符串鍵)能夠經過將鍵散列到64位整數來輕鬆實現。注意,每一個鍵最多隻能與一個二進制數值關聯;用同一個鍵保存兩個二進制數值會致使一個被另外一個覆蓋。咱們還將把鍵的概念稱爲id。node
GE支持具備原子性的單元上的高性能併發鍵值運算符。內置的原子單元操做符包括:AddCell、SaveCell、LoadCell和RemoveCell。使用特定鍵訪問單元格是序列化的;每一個人都按照必定的順序觀察一個做家所作的改變。c#
GE的耐久性是可選的。在編寫單元格以前,咱們能夠選擇是否向本地持久存儲提交預寫日誌(WAL)WAL保證了耐久性,但也帶來了一些性能損失。明智的使用它。緩存
數據存取模式:安全
GE提供了多種數據訪問模式。在決定使用這裏介紹的一種數據訪問方法以前,咱們應該權衡便利和性能之間的權衡。服務器
內置鍵值存儲接口:網絡
最方便的方法是使用內置的鍵-值存儲接口,好比SaveCell和LoadCell。在GE中,這些接口是在Trinity Global。用於分別在本地或集羣上訪問數據的CloudStorage。併發
內置接口將單元格視爲二進制數。在TSL中定義了本身的單元格類型以後,其餘類型的鍵-值存儲接口將綁定在Trinity.Global.LocalStorage Triity.Global.CloudStorage.TSL生成的接口採用LoadMyType和SaveMyType的形式。例如,若是咱們在TSL中定義一種單元格類型以下:ide
cell GraphNode
{
[Index]
string Name;
float Value;
List<CellId> Neighbors;
}性能
兩個新的接口LoadGraphNode和SaveGraphNode將綁定到LocalStorage和CloudStorage。爲這些接口提供了多個方法重載。咱們能夠這樣寫:
var root = Global.CloudStorage.LoadGraphNode(123); //123 as the cell id
var sum = 0.0f;
foreach(var neighbor in root.Neighbors)
{
sum += Global.CloudStorage.LoadGraphNode(neighbor).Value;
}
遠程選擇性數據訪問:
GE支持服務器端計算。這意味着咱們不須要將全部相關的單元放到網絡上,而後在本地對他們應用操做。咱們 經過網絡傳遞咱們感興趣的信息。爲此,咱們爲客戶機-服務器通訊定義了一個自定義協議。如今,咱們能夠向服務器發送用戶定義的請求,以得到所需的結果,而不是發送單元格加載/保存操做。例如,我了得到一組GraphNode值的和,咱們能夠定義這樣的協議,而不是將他們加載到客戶端:
struct RequestMessage
{
List<CellId> NodeSet;
}
struct ResponseMessage
{
float Result;
}
protocol CalculateSum
{
Type : Syn;
Request : RequestMessage;
Response : ResponseMessage;
}
在客戶端,咱們能夠經過:
var sum = 0.0f;
for(int serverId = 0; serverId < Global.ServerCount; serverId++)
{
using(var request = new RequestMessageWriter(new List<long>(){1,2,3}))
{
using(var response = Global.CloudStorage.CalculateSumToMyServer(serverId, request))
{
var sum += response.Result;
}
}
}
服務器端,邏輯實現以下:
public override void CalculateSumHandler(
RequestMessageReader request,
ResponseMessageWriter response)
{
response.Result = .0f;
foreach(var nodeId in request.NodeSet)
{
response.Result += Global.LocalStorage.LoadGraphNode(nodeId).Value;
}
}
單元訪問器:
實際上,咱們能夠經過鍵-值存儲接口執行任何數據訪問任務。但很快咱們會注意到,即便咱們只想訪問單個數據字段,整個單元格也須要加載。在上面顯示的代碼片斷中,對某個字段訪問單元格。對於每一個單元,GE首先在內存存儲中肯定其內存位置。而後它調用運行時來分配單元格對象,並將單元格內容從存儲複製到對象。而後,從對象中讀出該字段病將其輸入到外部計算循環中。
單元格修飾是一個棘手的問題。只需修改單元格的一小部分就須要三個單元格操做:加載單元格、修改單元格和保存 單元格。在這個過程當中產生的內存 副本浪費了大量的內存和網絡帶寬。並且,即便每一個單元操做都是原子操做,單元修改做爲一個總體也不是原子操做,由於不能保證三個單獨的單元操做做爲一個總體執行。
在瞭解了使用鍵-值存儲接口形成的問題以後,咱們如今給出瞭解決方法。在GE中,咱們經過一種稱爲數據訪問器的機制來解決上述問題。對於TSL腳本中定義的任何單元結構,TSL編譯器將自動生成單元訪問器。訪問器不擁有任何數據。相反,全部字段都做爲c#屬性提供;對這些屬性的操做將轉換爲對底層單元格二進制的就低內存操做。使服務器邏輯重寫爲:
public override void ComputeAverageHandler(
RequestMessageReader request,
ResponseMessageWriter response)
{
response.Result = .0f;
foreach(var nodeId in request.NodeSet)
{
using( var neighbor = Global.LocalStorage.UseGraphNode(nodeId) )
{
response.Result += neighbor.Value;
}
}
}
在這個新版本中,訪問相鄰節點的值,將訪問4個字節的內存。有關單元格訪問器的更多信息,請參閱:個人博客-TSL 訪問器
只要可能,使用單元格訪問器而不是鍵-值存儲接口來訪問數據。
單元訪問設置:
咱們能夠爲大多數單元格訪問接口提供單元格訪問選項。根據單元格接口,能夠應用下面列出的一個或多個選項。
public enum CellAccessOptions
{
// Throws an exception when a cell is not found.
ThrowExceptionOnCellNotFound,
// Returns null when a cell is not found.