/* Copyright (c) Microsoft Corporation All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, MERCHANTABLITY OR NON-INFRINGEMENT. See the Apache Version 2.0 License for specific language governing permissions and limitations under the License. */ using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Runtime.CompilerServices; using System.Threading.Tasks; using Microsoft.Research.Peloponnese.NotHttpClient; namespace Microsoft.Research.Dryad.Channel { public interface IDrLogging { void LogAssertion(string message, string file, string function, int line); void LogError(string message, string file, string function, int line); void LogWarning(string message, string file, string function, int line); void LogInformation(string message, string file, string function, int line); } internal class DryadLogger { private IDrLogging logger; public DryadLogger(IDrLogging l) { logger = l; } public IDrLogging Logger { get { return logger; } } public void LogAssert( string message, [CallerFilePath] string file = "(nofile)", [CallerMemberName] string function = "(nofunction)", [CallerLineNumber] int line = -1) { logger.LogAssertion(message, file, function, line); } public void LogError( string message, [CallerFilePath] string file = "(nofile)", [CallerMemberName] string function = "(nofunction)", [CallerLineNumber] int line = -1) { logger.LogError(message, file, function, line); } public void LogWarning( string message, [CallerFilePath] string file = "(nofile)", [CallerMemberName] string function = "(nofunction)", [CallerLineNumber] int line = -1) { logger.LogWarning(message, file, function, line); } public void LogInformation( string message, [CallerFilePath] string file = "(nofile)", [CallerMemberName] string function = "(nofunction)", [CallerLineNumber] int line = -1) { logger.LogInformation(message, file, function, line); } } internal class PeloponneseLogger : Microsoft.Research.Peloponnese.ILogger { private readonly IDrLogging logger; public PeloponneseLogger(IDrLogging l) { logger = l; } public void Log( string entry, [CallerFilePath] string file = "(nofile)", [CallerMemberName] string function = "(nofunction)", [CallerLineNumber] int line = -1) { logger.LogInformation(entry, file, function, line); } public void Stop() { } } public enum ErrorType { Open, IO, Close } internal class HttpClient { private static readonly string s_dummy; private static NotHttpClient s_client; static HttpClient() { s_dummy = "String to lock"; } public static void Initialize(IDrLogging logger) { lock (s_dummy) { if (s_client == null) { s_client = new NotHttpClient(false, 10, 30000, new PeloponneseLogger(logger)); } } } public static IHttpRequest Create(string uri) { return s_client.CreateRequest(uri); } } public class Buffer { public long offset; public int size; public IntPtr storage; public IntPtr handle; } public interface IReaderClient { void UpdateTotalLength(long totalLength); void ReceiveData(Buffer b, bool eof); void SignalError(ErrorType type, string reason); void DiscardBuffer(Buffer b); } public interface IManagedReader { bool IsLocal { get; } int OutstandingBuffers { get; } int BufferSize { get; } long TotalLength { get; } void Start(); void SupplyBuffer(Buffer b); void Interrupt(); void WaitForDrain(); void Close(); } public interface IWriterClient { void ReturnBuffer(Buffer b, ErrorType type, string errorMessage); } public interface IManagedWriter { int BufferSize { get; } long BufferAlignment { get; } bool BreakOnRecordBoundaries { get; } /// /// open the output and start writing /// void Start(); /// /// accept a buffer to be written. This can be called before Start(), in which /// case the buffer should be queued. (This happens when the number of open writers /// is being throttled.) If the buffer offset is negative, that means we should close /// the writer stream after all the preceding writes have been sent. /// /// The data to write /// true if the sender should block until some buffers have been written out bool Write(Buffer buffer); /// /// block the calling thread until the output has been completely written and all buffers /// have been returned to the IWriterClient /// void WaitForClose(); } public class Factory { public delegate IManagedReader ReaderFactory(Uri uri, int numberOfReaders, IReaderClient client, IDrLogging logger); public delegate IManagedWriter WriterFactory(Uri uri, int numberOfWriters, IWriterClient client, IDrLogging logger); public static Dictionary readers; public static Dictionary writers; static Factory() { readers = new Dictionary(); writers = new Dictionary(); HttpReader.Register(); AzureReader.Register(); AzureWriter.Register(); //FileWriter.Register(); } public static void RegisterReader(string scheme, ReaderFactory factory) { readers.Add(scheme, factory); } public static void RegisterWriter(string scheme, WriterFactory factory) { writers.Add(scheme, factory); } public static bool RecognizesReaderUri(string path) { try { var uri = new Uri(path); return readers.ContainsKey(uri.Scheme); } catch (Exception) { return false; } } public static bool RecognizesWriterUri(string path) { try { var uri = new Uri(path); return writers.ContainsKey(uri.Scheme); } catch (Exception) { return false; } } public static IManagedReader OpenReader(string path, int numberOfReaders, IReaderClient client, IDrLogging logger) { try { HttpClient.Initialize(logger); var uri = new Uri(path); return readers[uri.Scheme](uri, numberOfReaders, client, logger); } catch (Exception e) { DryadLogger l = new DryadLogger(logger); l.LogError("Caught exception opening reader " + e.ToString()); return null; } } public static IManagedWriter OpenWriter(string path, int numberOfWriters, IWriterClient client, IDrLogging logger) { try { HttpClient.Initialize(logger); var uri = new Uri(path); return writers[uri.Scheme](uri, numberOfWriters, client, logger); } catch (Exception e) { DryadLogger l = new DryadLogger(logger); l.LogError("Caught exception opening writer " + e.ToString()); return null; } } } }