/// <summary> /// Callback when slave receives MessageIoFlowUpdate. /// Typically one of these messages updates a batch of flows. /// This is a request from the Rate Controller to update state for the given flows. /// </summary> /// <param name="listParams"></param> /// <returns></returns> public OktoResultCodes CallbackMessageIoFlowUpdate(List <IoFlowMessageParams> listParams) { lock (LockFlows) { foreach (IoFlowMessageParams flowu in listParams) { IoFlow flow = DictIoFlow[flowu.FlowId]; parseControllerCommandString(flow, flowu.ParameterString); } } return(OktoResultCodes.OKTO_RESULT_SUCCESS); }
/// <summary> /// Callback when slave receives MessageIoFlowStatsQuery. /// The reply message generated herein provides stats for all flows of the current tenant. /// This is a request from Rate Controller to return stats for all flows for current tenant. /// </summary> /// <returns></returns> public List <IoFlowMessageParams> CallbackMessageIoFlowStatsQuery() { //Console.WriteLine("CallbackMessageIoFlowStatsQuery()"); List <IoFlowMessageParams> listStats = new List <IoFlowMessageParams>(); lock (LockFlows) { foreach (IoFlowMessageParams statsquery in DictFlowCreateParams.Values) { IoFlow flow = DictIoFlow[statsquery.FlowId]; listStats.Add(new IoFlowMessageParams(flow.FlowId, formatCacheStatsString(flow.FlowId), (byte)flow.Flags)); } } return(listStats); }
public LinkedListNode <FileCacheElement> nodeInFreeFileCacheList; // location in free file cache element linked list // // Constructor. // Copies InData locally public FileCacheElement(IoFlow InFlow, string InFileName, byte[] InData, UInt64 InFileOffset, uint copyOffset, uint InDataLength) { LockObj = new object(); fileName = InFileName; Flow = InFlow; Data = null; FileOffset = InFileOffset; DataLength = InDataLength; Dirty = false; nodeInList = null; nodeInDirtyList = null; nodeInFreeFileCacheList = null; if (InData != null) { Data = new byte[InDataLength]; Buffer.BlockCopy(InData, (int)copyOffset, Data, 0, (int)InDataLength); //Array.Copy(InData, copyOffset, Data, 0, InDataLength); } }
private FileCacheElement getFileCacheElement(IoFlow InFlow, string InFileName, byte[] InData, UInt64 InFileOffset, uint copyOffset, uint InDataLength) { FileCacheElement elemReturn; bool reused = false; lock (this.freeFileCacheElements) { if (this.freeFileCacheElements.Count > 0) { LinkedListNode <FileCacheElement> llNode = this.freeFileCacheElements.First; this.freeFileCacheElements.Remove(llNode); elemReturn = llNode.Value; reused = true; } else { elemReturn = new FileCacheElement(InFlow, InFileName, InData, InFileOffset, copyOffset, InDataLength); } } if (reused) { Debug.Assert(elemReturn.DataLength == InDataLength); elemReturn.fileName = InFileName; elemReturn.Flow = InFlow; // keep data elemReturn.Data = null; elemReturn.FileOffset = InFileOffset; elemReturn.DataLength = InDataLength; elemReturn.Dirty = false; elemReturn.nodeInList = null; elemReturn.nodeInDirtyList = null; if (InData != null) { Buffer.BlockCopy(InData, (int)copyOffset, elemReturn.Data, 0, (int)InDataLength); } } return(elemReturn); }
/// <summary> /// Callback when slave has received all create parameters for flows and raps from rate controller. /// This is a request from the Rate Controller to configure IoFlow diver state for current tenant. /// </summary> /// <param name="dictFlowParams">Flow create params keyed on FlowId.</param> /// <param name="dictRapParams">RAP create params keyed on FlowId.</param> /// <returns></returns> public OktoResultCodes CallbackIoFlowCreate( Dictionary <uint, IoFlowMessageParams> dictFlowParams, Dictionary <uint, MsgRapArg> dictRapParams) { lock (LockFlows) { DictFlowCreateParams = dictFlowParams; DictRapCreateParams = dictRapParams; foreach (uint flowId in DictFlowCreateParams.Keys) { IoFlowMessageParams flowc = DictFlowCreateParams[flowId]; MsgRapArg rapc = DictRapCreateParams[flowId]; string[] separators = new string[] { " ", "\t" }; string[] toks = flowc.ParameterString.Split(separators, StringSplitOptions.RemoveEmptyEntries); string vmName = toks[1]; string volumeName = toks[4]; UInt64 flowCacheSize = Convert.ToUInt64(toks[5]); UInt32 ghostCacheBlockSize = Convert.ToUInt32(toks[6]); string writePolicy = toks[7]; string writeCachePolicy = toks[8]; UInt64 fileCacheTotalSize = Convert.ToUInt64(toks[9]); if (cache == null) //Create a file cache when we get the first request for a flow create { this.cache = new FileCache(fileCacheTotalSize, noisyOutput); } string thisMachine = System.Environment.MachineName.ToLower(); string ctrlFileName = rapc.ShareOrVolume; string ctrlHostName = null; string fileName = null; if (ctrlFileName.Substring(0, 2).Equals(@"\\")) { ctrlHostName = ctrlFileName.Substring(2); } else if (ctrlFileName.Substring(0, 1).Equals(@"\")) { ctrlHostName = ctrlFileName.Substring(1); } else { Debug.Assert(0 == 1); //all strings from the controller should start like that } int idxEndHostName = ctrlHostName.IndexOf(@"\"); string shareFile = ctrlHostName.Substring(idxEndHostName); ctrlHostName = ctrlHostName.Substring(0, idxEndHostName); if (ctrlHostName.Equals(thisMachine)) { fileName = this.runtime.getDriveLetterFileName(volumeName + shareFile); } else { fileName = ctrlFileName; } // Params look reasonable and FlowCreate and RapCreate match up: create the IoFlow here. IoFlow f1 = runtime.CreateFlow(flowId, vmName, fileName, PreCreate, null, PreRead, PostRead, PreWrite, PostWrite, PreCleanup, null, null, null); //Set the remaining init parameters that are also dynamically change-able cache.CacheSetFlowSize(flowId, flowCacheSize); #if USE_GHOST_CACHE cache.CacheCreateGhostCache(f1.FlowId, ghostCacheBlockSize); #endif switch (writePolicy) { case "write-through": cache.SetCacheWritePolicy(CacheWritePolicy.WriteThrough); break; } switch (writeCachePolicy) { case "CacheWrites": cache.SetCacheWriteBuffering(CacheWriteBuffer.Cache); break; case "noCacheWrites": cache.SetCacheWriteBuffering(CacheWriteBuffer.noCache); break; } DictIoFlow.Add(flowc.FlowId, f1); } } return(OktoResultCodes.OKTO_RESULT_SUCCESS); }
private void parseControllerCommandString(IoFlow flow, string controllerCommand) { string[] commandStringSeparators = new string[] { " ", "\t" }; char[] tokenSeparator = new char[] { '=' }; string[] commandTokens = controllerCommand.Split(commandStringSeparators, StringSplitOptions.RemoveEmptyEntries); if (commandTokens.Length > 0) { Console.WriteLine("CallbackMessageIoFlowUpdate({0},{1})", flow.FlowId, controllerCommand); foreach (string token in commandTokens) { string param = token.Split(tokenSeparator)[0]; string value = token.Split(tokenSeparator)[1]; //Switch to the appropriate handler switch (param) { case "changeCacheSize": this.cache.CacheSetFlowSize(flow.FlowId, Convert.ToUInt64(value)); break; case "changeWritePolicy": switch (value) { case "write-through": this.cache.SetCacheWritePolicy(CacheWritePolicy.WriteThrough); break; default: Console.WriteLine("Command value invalid"); Debug.Assert(0 == 1); break; } break; case "changeOpPolicy": string op = value.Split(',')[0]; string policy = value.Split(',')[1]; switch (op) { case "W": switch (policy) { case "yes": this.cache.SetCacheWriteBuffering(CacheWriteBuffer.Cache); //Cache writes break; case "no": this.cache.SetCacheWriteBuffering(CacheWriteBuffer.noCache); //Don't cache writes break; default: Console.WriteLine("Command value invalid"); Debug.Assert(0 == 1); break; } break; case "R": //Nothing for now; add fine-grained control to cache/not cache reads here break; default: Console.WriteLine("Command value invalid"); Debug.Assert(0 == 1); break; } break; default: Console.WriteLine("Controller command invalid"); Debug.Assert(0 == 1); break; } } } }
public bool Start() { string thisMachine = System.Environment.MachineName.ToLower(); // // Initialize IoFlow runtime. // IoFlowRuntime runtime = new IoFlowRuntime((uint)Mpl); string line; // get info from config file Debug.Assert(inputConfig != null && File.Exists(inputConfig)); string[] separators = new string[] { " ", "\t" }; System.IO.StreamReader f = new System.IO.StreamReader(inputConfig); // line has entries SRV_NAME, VM_NAME, VHD_NAME, cacheSizeMB, IO_req_size, write-back/write-through, noCacheWrites/cacheWrites while ((line = f.ReadLine()) != null) { string[] tokens = line.Split(separators, StringSplitOptions.RemoveEmptyEntries); if (tokens.Length == 0) { continue; } else if (tokens[0].StartsWith(@"#") || tokens[0].StartsWith(@"//")) { continue; } if (tokens.Length < 7) { throw new ApplicationException(String.Format("invalid config file")); } if (!(tokens[5].Equals("write-through") || tokens[5].Equals("write-back"))) { throw new ApplicationException(String.Format("invalid config file")); } if (!(tokens[6].Equals("cacheWrites") || tokens[6].Equals("noCacheWrites"))) { throw new ApplicationException(String.Format("invalid config file")); } Console.WriteLine("Got tokens {0}, {1}, {2}, {3}, {4}, {5}, {6}", tokens[0], tokens[1], tokens[2], tokens[3], tokens[4], tokens[5], tokens[6]); if (thisMachine.StartsWith(tokens[0].ToLower())) { IoFlow f1 = runtime.CreateFlow(runtime.GetNextFreeFlowId(), tokens[1].ToLower(), tokens[2].ToLower(), PreCreate, null, PreRead, PostRead, PreWrite, PostWrite, PreCleanup, null, null, null); cache.CacheSetFlowSize(f1.FlowId, Convert.ToUInt64(tokens[3])); //cache.CacheCreateGhostCache(f1.FlowId, Convert.ToUInt32(tokens[4])); //XXXIS: this should come from the controller... cache.AlignedBlockSize = Convert.ToUInt32(tokens[4]); switch (tokens[5]) { case "write-through": cache.SetCacheWritePolicy(CacheWritePolicy.WriteThrough); break; } switch (tokens[6]) { case "cacheWrites": cache.SetCacheWriteBuffering(CacheWriteBuffer.Cache); break; case "noCacheWrites": cache.SetCacheWriteBuffering(CacheWriteBuffer.noCache); break; } } } runtime.Start(false); CacheThreadBlocked.WaitOne(); runtime.Close(); return(true); }