/// <summary> /// Creates the pipeline for streaming the block to DataNodes /// </summary> /// <param name="blockInfo">Info of the block. Contains blockid, blocksize, and ipaddresses for pipeline creation</param> /// <param name="client">Client connection with first DataNode in pipe</param> /// <returns>Success of pipeline creation</returns> private bool GetPipeLineReady(ClientProto.BlockInfo blockInfo, out ClientProto.ClientProto.ClientProtoClient client) { ClientProto.StatusResponse readyResponse = new ClientProto.StatusResponse { Type = ClientProto.StatusResponse.Types.StatusType.Fail }; try { Channel channel = new Channel(blockInfo.IpAddress[0] + ":" + "50051", ChannelCredentials.Insecure); blockInfo.IpAddress.RemoveAt(0); client = new ClientProto.ClientProto.ClientProtoClient(channel); readyResponse = client.GetReady(blockInfo); return(true); } catch (Exception e) { #if Debug Console.WriteLine("Get ready failed: " + e.Message); #endif client = null; return(false); } }
/// <summary> /// Creates the pipeline and writes to datanode /// </summary> /// <param name="blockInfo">Info of the block. Contains blockid, blocksize, and ipaddresses for pipeline creation</param> /// <param name="block">data of block</param> /// <returns>Returns true if streaming of data through newly created pipeline was successful</returns> private bool CreatePipelineAndWrite(ClientProto.BlockInfo blockInfo, byte[] block, long contentLength) { // Create pipeline from list if (GetPipeLineReady(blockInfo, out ClientProto.ClientProto.ClientProtoClient writeClient)) { if (client != null) { try { // Send block through pipeline WriteBlock(writeClient, blockInfo, block, contentLength).Wait(); return(true); } catch (Exception e) { #if Debug Console.WriteLine(e.Message); #endif return(false); } } } return(false); }
public ClientProto.BlockInfo AddBlockToFile(ClientProto.BlockInfo addedBlock) { try { string path = addedBlock.FullPath; string name = TraverseFileSystem(path); FileSystem.File file = CurrentDirectory.files[name]; file.fileSize += addedBlock.BlockSize; // to be used to send back a write request to the client List <string> responseRequests = new List <string>(); // stores blockID and adds it to the file. Guid id = Guid.Parse(addedBlock.BlockId.Value); if (!file.data.Contains(id)) { file.data.Add(id); } List <string> ipAddresses = DataNodeManager.Instance.GetDataNodesForReplication(); // add it to the BlockID to DataNode Dictionary BlockID_To_ip.TryAdd(id, new List <string>()); SaveFileDirectory(); return(new ClientProto.BlockInfo { BlockId = new ClientProto.UUID { Value = id.ToString() }, FullPath = path, BlockSize = addedBlock.BlockSize, IpAddress = { ipAddresses } }); } catch (Exception e) { Console.WriteLine(e.Message); return(null); } }
/// <summary> /// Writes the block to the first DataNode /// </summary> /// <param name="client">Client Connection to the first DataNode</param> /// <param name="blockInfo">Info of the block. Contains blockid, blocksize, and ipaddresses for pipeline creation</param> /// <param name="block">Data of block</param> /// <returns>Task of the write or Exception on fail</returns> private async Task WriteBlock(ClientProto.ClientProto.ClientProtoClient client, ClientProto.BlockInfo blockInfo, byte[] block, long contentLength) { Metadata metaData = new Metadata { new Metadata.Entry("blockid", blockInfo.BlockId.Value), new Metadata.Entry("blocksize", blockInfo.BlockSize.ToString()) }; int totalBytesRead = 0; using (var call = client.WriteBlock(metaData)) { bool dataNodeFailed = false; while (totalBytesRead < blockInfo.BlockSize) { int length = Math.Min(Constants.ChunkSize, blockInfo.BlockSize - totalBytesRead); // Make sure correct length of data is sent byte[] chunk = new byte[length]; Buffer.BlockCopy(block, totalBytesRead, chunk, 0, length); totalBytesRead += length; TotalBytesWrittenFromFile += length; try { await call.RequestStream.WriteAsync(new ClientProto.BlockData { Data = Google.Protobuf.ByteString.CopyFrom(chunk) }); // Casts are very necessary here! Console.Write("\rWriting File {0}", (((double)TotalBytesWrittenFromFile / (double)contentLength)).ToString("0.00%")); } catch (Exception e) { dataNodeFailed = true; totalBytesRead = blockInfo.BlockSize; // Stop reading #if Debug throw new Exception("Writing block failed", e); #endif } } ClientProto.StatusResponse resp = new ClientProto.StatusResponse { Type = ClientProto.StatusResponse.Types.StatusType.Fail }; if (!dataNodeFailed) { await call.RequestStream.CompleteAsync(); resp = await call.ResponseAsync; } if (resp.Type == ClientProto.StatusResponse.Types.StatusType.Fail) { throw new Exception("Writing block failed"); } } }
/// <summary> /// Processes stream in order to read the file /// </summary> /// <param name="stream">Stream of the file</param> /// <param name="contentLength">Length of the file</param> private void ProcessStream(Stream stream, long contentLength) { // Read from response stream until entire file is read long totalBytesRead = 0; byte[] block = new byte[Constants.BlockSize]; while (totalBytesRead < contentLength) { try { int bytesRead = 0; // Read until block size or until all the file has been read while (bytesRead < Constants.BlockSize && totalBytesRead != contentLength) { int length = Math.Min(block.Length, Constants.BlockSize - bytesRead); int n = stream.Read(block, bytesRead, length); bytesRead += n; totalBytesRead += n; } ClientProto.BlockInfo blockInfo = new ClientProto.BlockInfo { BlockId = new ClientProto.UUID { Value = Guid.NewGuid().ToString() }, FullPath = filePath, BlockSize = bytesRead }; bool writeSuccess = false; while (!writeSuccess) { // Keep asking NameNode for new DataNodes if all fail // Get DataNode locations to store block blockInfo = client.QueryBlockDestination(blockInfo); if (blockInfo.IpAddress.Count() == 0) { Console.WriteLine("SUFS is unavailable"); Environment.Exit(1); } for (int i = 0; i < blockInfo.IpAddress.Count(); i++) { // Need to reassign because classes are passed by reference and we are removing nodes ClientProto.BlockInfo info = new ClientProto.BlockInfo { BlockId = blockInfo.BlockId, BlockSize = blockInfo.BlockSize, FullPath = blockInfo.FullPath, }; info.IpAddress.AddRange(blockInfo.IpAddress); if (CreatePipelineAndWrite(info, block, contentLength)) { writeSuccess = true; break; } else { if (blockInfo.IpAddress.Count() <= 1) { Console.WriteLine("SUFS is unavailable"); Environment.Exit(1); } // Try a different datanode first. // This has a chance because this flow only fails if the first datanode fails to connect or somehow they all fail. var tempAddresses = blockInfo.IpAddress.Shift(); blockInfo.IpAddress.Clear(); blockInfo.IpAddress.AddRange(tempAddresses); } } } } catch (RpcException e) { // Stop reading totalBytesRead = contentLength; Console.WriteLine("Failed to write file: " + e.Message); } catch (Exception e) { #if Debug Console.WriteLine(e.Message); #endif } } }
public override Task <ClientProto.BlockInfo> QueryBlockDestination(ClientProto.BlockInfo blockInfo, ServerCallContext context) { return(Task.FromResult(Program.Database.AddBlockToFile(blockInfo))); }