private Task <PreparedStatement> SetPrepareTableInfo(PreparedStatement ps) { const string msgRoutingNotSet = "Routing information could not be set for query \"{0}\""; var column = ps.Metadata.Columns.FirstOrDefault(); if (column == null || column.Keyspace == null) { //The prepared statement does not contain parameters return(TaskHelper.ToTask(ps)); } if (ps.Metadata.PartitionKeys != null) { //The routing indexes where parsed in the prepared response if (ps.Metadata.PartitionKeys.Length == 0) { //zero-length partition keys means that none of the parameters are partition keys //the partition key is hard-coded. return(TaskHelper.ToTask(ps)); } ps.RoutingIndexes = ps.Metadata.PartitionKeys; return(TaskHelper.ToTask(ps)); } return(Cluster.Metadata.GetTableAsync(column.Keyspace, column.Table).ContinueWith(t => { if (t.Exception != null) { Logger.Error("There was an error while trying to retrieve table metadata for {0}.{1}. {2}", column.Keyspace, column.Table, t.Exception.InnerException); return ps; } var table = t.Result; if (table == null) { Logger.Info(msgRoutingNotSet, ps.Cql); return ps; } var routingSet = ps.SetPartitionKeys(table.PartitionKeys); if (!routingSet) { Logger.Info(msgRoutingNotSet, ps.Cql); } return ps; })); }
public override Task <FunctionMetadata> GetFunction(string keyspaceName, string functionName, string signatureString) { var query = string.Format(SelectFunctions, keyspaceName, functionName, signatureString); return(Cc .QueryAsync(query, true) .Then(rs => { var row = rs.FirstOrDefault(); if (row == null) { return TaskHelper.ToTask <FunctionMetadata>(null); } var argumentTypes = row.GetValue <string[]>("argument_types") ?? new string[0]; var parseTasks = new Task <ColumnDesc> [1 + argumentTypes.Length]; parseTasks[0] = DataTypeParser.ParseTypeName(_udtResolver, row.GetValue <string>("keyspace_name"), row.GetValue <string>("return_type")); for (var i = 0; i < argumentTypes.Length; i++) { parseTasks[1 + i] = DataTypeParser.ParseTypeName(_udtResolver, row.GetValue <string>("keyspace_name"), argumentTypes[i]); } return Task.Factory.ContinueWhenAll(parseTasks, tasks => { var ex = tasks.Select(t => t.Exception).FirstOrDefault(e => e != null); if (ex != null) { throw ex.InnerException; } return new FunctionMetadata { Name = row.GetValue <string>("function_name"), KeyspaceName = row.GetValue <string>("keyspace_name"), Signature = argumentTypes, ArgumentNames = row.GetValue <string[]>("argument_names") ?? new string[0], Body = row.GetValue <string>("body"), CalledOnNullInput = row.GetValue <bool>("called_on_null_input"), Language = row.GetValue <string>("language"), ReturnType = tasks[0].Result, ArgumentTypes = tasks.Skip(1).Select(t => t.Result).ToArray() }; }); })); }
internal Task <TableMetadata> GetTableMetadataAsync(string tableName) { TableMetadata tableMetadata; if (_tables.TryGetValue(tableName, out tableMetadata)) { //The table metadata is available in local cache return(TaskHelper.ToTask(tableMetadata)); } return(_parent.SchemaParser .GetTable(Name, tableName) .ContinueSync(table => { if (table == null) { return null; } //Cache it _tables.AddOrUpdate(tableName, table, (k, o) => table); return table; })); }
private Task <T> ParseTableOrView <T>(Func <Row, T> newInstance, Task <IEnumerable <Row> > getTableTask, Task <IEnumerable <Row> > getColumnsTask) where T : DataCollectionMetadata { var tableMetadataRow = getTableTask.Result.FirstOrDefault(); if (tableMetadataRow == null) { return(TaskHelper.ToTask <T>(null)); } var columns = new Dictionary <string, TableColumn>(); var partitionKeys = new List <Tuple <int, TableColumn> >(); var clusteringKeys = new List <Tuple <int, Tuple <TableColumn, SortOrder> > >(); //Read table options var options = new TableOptions { isCompactStorage = false, bfFpChance = tableMetadataRow.GetValue <double>("bloom_filter_fp_chance"), caching = "{" + string.Join(",", tableMetadataRow.GetValue <IDictionary <string, string> >("caching").Select(kv => "\"" + kv.Key + "\":\"" + kv.Value + "\"")) + "}", comment = tableMetadataRow.GetValue <string>("comment"), gcGrace = tableMetadataRow.GetValue <int>("gc_grace_seconds"), localReadRepair = tableMetadataRow.GetValue <double>("dclocal_read_repair_chance"), readRepair = tableMetadataRow.GetValue <double>("read_repair_chance"), compactionOptions = tableMetadataRow.GetValue <SortedDictionary <string, string> >("compaction"), compressionParams = tableMetadataRow.GetValue <SortedDictionary <string, string> >("compression") }; var columnsMetadata = getColumnsTask.Result; Task <Tuple <TableColumn, Row> >[] columnTasks = columnsMetadata .Select(row => { return(DataTypeParser.ParseTypeName(_udtResolver, tableMetadataRow.GetValue <string>("keyspace_name"), row.GetValue <string>("type")). ContinueSync(type => Tuple.Create(new TableColumn { Name = row.GetValue <string>("column_name"), Keyspace = row.GetValue <string>("keyspace_name"), Table = row.GetValue <string>("table_name"), TypeCode = type.TypeCode, TypeInfo = type.TypeInfo }, row))); }).ToArray(); return(Task.Factory.ContinueWhenAll(columnTasks, tasks => { var ex = tasks.Select(t => t.Exception).FirstOrDefault(e => e != null); if (ex != null) { throw ex.InnerException; } foreach (var t in tasks) { var col = t.Result.Item1; var row = t.Result.Item2; switch (row.GetValue <string>("kind")) { case "partition_key": partitionKeys.Add(Tuple.Create(row.GetValue <int?>("position") ?? 0, col)); col.KeyType = KeyType.Partition; break; case "clustering": clusteringKeys.Add(Tuple.Create(row.GetValue <int?>("position") ?? 0, Tuple.Create(col, row.GetValue <string>("clustering_order") == "desc" ? SortOrder.Descending : SortOrder.Ascending))); col.KeyType = KeyType.Clustering; break; case "static": col.IsStatic = true; break; } columns.Add(col.Name, col); } if (typeof(T) == typeof(TableMetadata)) { var flags = tableMetadataRow.GetValue <string[]>("flags"); var isDense = flags.Contains("dense"); var isSuper = flags.Contains("super"); var isCompound = flags.Contains("compound"); options.isCompactStorage = isSuper || isDense || !isCompound; //remove the columns related to Thrift var isStaticCompact = !isSuper && !isDense && !isCompound; if (isStaticCompact) { PruneStaticCompactTableColumns(clusteringKeys, columns); } else if (isDense) { PruneDenseTableColumns(columns); } } var result = newInstance(tableMetadataRow); result.SetValues(columns, partitionKeys.OrderBy(p => p.Item1).Select(p => p.Item2).ToArray(), clusteringKeys.OrderBy(p => p.Item1).Select(p => p.Item2).ToArray(), options); return result; })); }
/// <summary> /// Initializes the connection. /// </summary> /// <exception cref="SocketException">Throws a SocketException when the connection could not be established with the host</exception> /// <exception cref="AuthenticationException" /> /// <exception cref="UnsupportedProtocolVersionException"></exception> public Task <Response> Open() { _freeOperations = new ConcurrentStack <short>(Enumerable.Range(0, MaxConcurrentRequests).Select(s => (short)s).Reverse()); _pendingOperations = new ConcurrentDictionary <short, OperationState>(); _writeQueue = new ConcurrentQueue <OperationState>(); if (Options.CustomCompressor != null) { Compressor = Options.CustomCompressor; } else if (Options.Compression == CompressionType.LZ4) { Compressor = new LZ4Compressor(); } else if (Options.Compression == CompressionType.Snappy) { Compressor = new SnappyCompressor(); } //Init TcpSocket _tcpSocket.Init(); _tcpSocket.Error += CancelPending; _tcpSocket.Closing += () => CancelPending(null, null); //Read and write event handlers are going to be invoked using IO Threads _tcpSocket.Read += ReadHandler; _tcpSocket.WriteCompleted += WriteCompletedHandler; return(_tcpSocket .Connect() .Then(_ => Startup()) .ContinueWith(t => { if (t.IsFaulted && t.Exception != null) { //Adapt the inner exception and rethrow var ex = t.Exception.InnerException; var protocolVersion = _serializer.ProtocolVersion; if (ex is ProtocolErrorException) { //As we are starting up, check for protocol version errors //There is no other way than checking the error message from Cassandra if (ex.Message.Contains("Invalid or unsupported protocol version")) { throw new UnsupportedProtocolVersionException(protocolVersion, ex); } } if (ex is ServerErrorException && protocolVersion >= 3 && ex.Message.Contains("ProtocolException: Invalid or unsupported protocol version")) { //For some versions of Cassandra, the error is wrapped into a server error //See CASSANDRA-9451 throw new UnsupportedProtocolVersionException(protocolVersion, ex); } throw ex; } return t.Result; }, TaskContinuationOptions.ExecuteSynchronously) .Then(response => { if (response is AuthenticateResponse) { return StartAuthenticationFlow(((AuthenticateResponse)response).Authenticator); } if (response is ReadyResponse) { return TaskHelper.ToTask(response); } throw new DriverInternalError("Expected READY or AUTHENTICATE, obtained " + response.GetType().Name); })); }
/// <summary> /// Create the min amount of connections, if the pool is empty /// </summary> /// <exception cref="System.Net.Sockets.SocketException" /> internal Task <Connection[]> MaybeCreateCorePool() { var coreConnections = _config.GetPoolingOptions(ProtocolVersion).GetCoreConnectionsPerHost(_distance); if (!_connections.Any(c => c.IsClosed) && _connections.Count >= coreConnections) { //Pool has the appropriate size return(TaskHelper.ToTask(_connections.ToArray())); } if (!_poolModificationSemaphore.Wait(0)) { //Couldn't enter semaphore, check if there is a connection available to yield var opened = _connections.Where(c => !c.IsClosed).ToArray(); if (opened.Length > 0) { return(TaskHelper.ToTask(opened)); } var alreadyOpening = _openingConnections; if (alreadyOpening != null && alreadyOpening.Length > 0) { return(Task.Factory.ContinueWhenAny(alreadyOpening, t => { if (t.Status == TaskStatus.RanToCompletion) { return new[] { t.Result }; } if (t.Exception != null) { throw t.Exception.InnerException; } throw new TaskCanceledException("Could not get an opened connection because the Task was cancelled"); }, TaskContinuationOptions.ExecuteSynchronously)); } //There isn't a connection available yet, enter semaphore _poolModificationSemaphore.Wait(); } //Semaphore entered //Remove closed connections from the pool var toRemove = _connections.Where(c => c.IsClosed).ToArray(); foreach (var c in toRemove) { _connections.Remove(c); } var opening = new List <Task <Connection> >(); if (_openingConnections != null) { opening.AddRange(_openingConnections); } while (_connections.Count + opening.Count < coreConnections) { opening.Add(CreateConnection()); } if (opening.Count == 0) { if (_connections.Count == 0) { return(TaskHelper.FromException <Connection[]>(new DriverInternalError("Could not create a connection and no connections found in pool"))); } _poolModificationSemaphore.Release(); return(TaskHelper.ToTask(_connections.ToArray())); } var openingArray = opening.ToArray(); _openingConnections = openingArray; //Clean up when all open task finished var allCompleted = Task.Factory.ContinueWhenAll(openingArray, tasks => { _connections.AddRange(tasks.Where(t => t.Status == TaskStatus.RanToCompletion).Select(t => t.Result).ToArray()); if (_connections.Count == coreConnections) { Logger.Info("{0} connection(s) to host {1} {2} created successfully", coreConnections, _host.Address, _connections.Count < 2 ? "was" : "were"); _host.BringUpIfDown(); } _openingConnections = null; var connectionsArray = _connections.ToArray(); _poolModificationSemaphore.Release(); if (connectionsArray.Length == 0 && tasks.All(t => t.Status != TaskStatus.RanToCompletion)) { //Pool could not be created Logger.Info("Connection pool to host {0} could not be created", _host.Address); //There are multiple problems, but we only care about one // ReSharper disable once PossibleNullReferenceException throw tasks.First().Exception.InnerException; } return(connectionsArray); }, TaskContinuationOptions.ExecuteSynchronously); //yield the first connection available return(Task.Factory.ContinueWhenAny(openingArray, t => { if (t.Status == TaskStatus.RanToCompletion) { return new[] { t.Result }; } if (t.Exception != null) { throw t.Exception.InnerException; } throw new TaskCanceledException("Could not get an opened connection because the Task was cancelled"); }, TaskContinuationOptions.ExecuteSynchronously) .ContinueWith(t => { if (t.Status != TaskStatus.RanToCompletion) { //The first connection failed //Wait for all to complete return allCompleted; } return TaskHelper.ToTask(t.Result); }, TaskContinuationOptions.ExecuteSynchronously).Unwrap()); }