/*
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.Diagnostics;
using System.Linq.Expressions;
using System.Reflection;
using System.IO;
using Microsoft.Research.DryadLinq.Internal;
namespace Microsoft.Research.DryadLinq
{
///
/// Represents the context necessary to prepare and execute a HPC LINQ Query,
///
///
///
/// HpcLinqContext is the main entry point for the HPC LINQ framework. The context
/// that is maintained by a HpcLinqContext instance includes configuration information, a connection to a DSC Service
/// that can be used during execution, and a connection to a HPC Server.
///
///
/// A HpcLinqContext may be reused by multiple queries and query executions.
///
///
/// A HpcLinqContext may hold open connections to DSC and a HPC Server. To release these connections, call
/// HpcLinqContext.Dispose()
///
///
public sealed class HpcLinqContext : IDisposable
{
private HpcLinqConfiguration _configuration;
private HpcQueryRuntime _runtime;
private DscService _dscService;
private string _hdfsServiceNode;
private Version _clientVersion;
private Version _serverVersion;
///
/// Gets the configuration associated with this HpcLinqContext.
///
///
/// The Configuration object returns will be read-only.
///
public HpcLinqConfiguration Configuration
{
get {
ThrowIfDisposed();
return _configuration;
}
}
///
/// Gets the DscService associated with this HpcLinqContext.
///
public DscService DscService
{
get
{
ThrowIfDisposed();
return _dscService;
}
}
///
/// Gets the HdfsService associated with this HpcLinqContext.
///
public string HdfsService
{
get
{
ThrowIfDisposed();
return _hdfsServiceNode;
}
}
// internal: the runtime associated with this HpcLinqContext.
internal HpcQueryRuntime Runtime {
get
{
ThrowIfDisposed();
return _runtime;
}
}
///
/// Version of the HpcLinq client components
///
public Version ClientVersion {
get {
ThrowIfDisposed();
if (_clientVersion == null)
{
LoadClientVersion(); // thread-safe
}
return _clientVersion;
}
}
///
/// Version of the HpcLinq server components
///
public Version ServerVersion {
get
{
ThrowIfDisposed();
if (_serverVersion == null)
{
LoadServerVersion(); // thread-safe
}
return _serverVersion;
}
}
///
/// Initializes a new instance of the HpcLinqConfiguration class.
///
/// Configuration information.
///
/// Connections will be opened to DSC and HPC Server using configuration.HeadNode.
/// The connections will be opened regardless of whether DSC is used and/or whether
/// configuration.LocalDebug is true
///
public HpcLinqContext(HpcLinqConfiguration configuration)
{
// Verify that the head node is set
if (configuration.HeadNode == null)
{
throw new DryadLinqException(HpcLinqErrorCode.ClusterNameMustBeSpecified,
SR.ClusterNameMustBeSpecified);
}
_configuration = configuration.MakeImmutableCopy();
_runtime = new HpcQueryRuntime(_configuration.HeadNode);
_dscService = new DscService(_configuration.HeadNode);
_hdfsServiceNode = _configuration.HdfsNameNode;
}
private void LoadClientVersion()
{
try
{
Assembly asm = Assembly.GetExecutingAssembly();
_clientVersion = new Version(FileVersionInfo.GetVersionInfo(asm.Location).FileVersion);
}
catch (Exception ex)
{
throw new DryadLinqException(HpcLinqErrorCode.CouldNotGetClientVersion,
SR.CouldNotGetClientVersion, ex);
}
}
private void LoadServerVersion()
{
try
{
IServerVersion version = this.GetIScheduler().GetServerVersion();
_serverVersion = new Version(version.Major, version.Minor, version.Build, version.Revision);
}
catch (Exception ex)
{
throw new DryadLinqException(HpcLinqErrorCode.CouldNotGetServerVersion,
SR.CouldNotGetServerVersion, ex);
}
}
///
/// Open a DSC fileset as a LINQ-to-HPC IQueryable{T}.
///
/// The type of the records in the table.
/// The name of the DSC fileset.
/// An IQueryable{T} representing the data and associated with the HPC LINQ query provider.
public IQueryable FromDsc(string fileSetName)
{
ThrowIfDisposed();
string fullPath = DataPath.MakeDscStreamUri(_dscService, fileSetName);
try {
DscFileSet fs = _dscService.GetFileSet(fileSetName);
if (!fs.IsSealed())
{
throw new DryadLinqException(HpcLinqErrorCode.FileSetMustBeSealed,
SR.FileSetMustBeSealed);
}
int fileCount = fs.GetFiles().Count();
if (fileCount < 1)
{
throw new DryadLinqException(HpcLinqErrorCode.FileSetMustHaveAtLeastOneFile,
SR.FileSetMustHaveAtLeastOneFile);
}
}
catch (DscException dscEx){
throw new DryadLinqException(HpcLinqErrorCode.FileSetCouldNotBeOpened,
SR.FileSetCouldNotBeOpened, dscEx);
}
DryadLinqQuery q = DataProvider.GetPartitionedTable(this, fullPath);
q.CheckAndInitialize(); // force the data-info checks.
return q;
}
///
/// Open a HDFS fileset as an IQueryable{T}.
///
/// The type of the records in the table.
/// The name of the HDFS fileset.
/// An IQueryable{T} representing the data and associated with the HPC LINQ query provider.
public IQueryable FromHdfs(string fileSetName)
{
ThrowIfDisposed();
string fullPath = DataPath.MakeHdfsStreamUri(_hdfsServiceNode, fileSetName);
return DataProvider.GetPartitionedTable(this, fullPath);
}
///
/// Converts an IEnumerable{T} to a LINQ-to-HPC IQueryable{T}.
///
/// The type of the records in the table.
/// The source data.
/// An IQueryable{T} representing the data and associated with the HPC LINQ query provider.
///
/// The source data will be serialized to a DSC fileset using the LINQ-to-HPC serialization approach.
/// The resulting fileset will have an auto-generated name and a temporary lease.
///
public IQueryable FromEnumerable(IEnumerable data)
{
string fileSetName = DataPath.MakeUniqueTemporaryDscFileSetName();
DscCompressionScheme compressionScheme = Configuration.IntermediateDataCompressionScheme;
DryadLinqMetaData metadata = DryadLinqMetaData.ForLocalDebug(this, typeof(T), fileSetName, compressionScheme);
return DataProvider.IngressTemporaryDataDirectlyToDsc(this, data, fileSetName, metadata, compressionScheme);
}
///
/// Releases all resources used by the HpcLinqContext.
///
public void Dispose()
{
_configuration = null;
if (_runtime != null)
{
_runtime.Dispose();
_runtime = null;
}
if (_dscService != null)
{
_dscService.Close();
_dscService = null;
}
}
internal static HpcLinqContext GetContext(DryadLinqProviderBase provider)
{
HpcLinqContext context = provider.Context;
Debug.Assert(context != null, "A context should always be associated with a HpcLinqQuery");
context.ThrowIfDisposed();
return context;
}
// Return IScheduler reference for internal use
internal IScheduler GetIScheduler()
{
return _runtime.GetIScheduler();
}
internal void ThrowIfDisposed()
{
if (_configuration == null)
{
throw new DryadLinqException(HpcLinqErrorCode.ContextDisposed,
SR.ContextDisposed);
}
}
}
}