private List <FanoutPathDescriptor> _GetOriginPathDescriptors(FanoutQueryMessageReader request) { List <FanoutPathDescriptor> origins = new List <FanoutPathDescriptor>(); if (request.originQuery.Length == 0) // no query string for origin. use the provided origin IDs. { origins.AddRange(request.origin.Select(_ => new FanoutPathDescriptor(_))); Log.WriteLine(LogLevel.Debug, "FanoutSearchQueryHandler: origin = {0}", string.Join(",", request.origin)); } else // use the query string to get origin IDs. { try { Log.WriteLine(LogLevel.Debug, "FanoutSearchQueryHandler: origin query string = {0}", request.originQuery); JObject query_object = JObject.Parse(request.originQuery); object match_object = query_object[JsonDSL.Match]; string type_string = (string)query_object[JsonDSL.Type]; origins.AddRange(s_indexServiceFunc(match_object, type_string).Select(_ => new FanoutPathDescriptor(_))); } catch (IndexingServiceNotRegisteredException) { Log.WriteLine(LogLevel.Error, "FanoutSearchQueryHandler: index service not registered."); return(null); } catch (Exception ex) { Log.WriteLine(LogLevel.Error, "Failed to query index service: {0}", ex.ToString()); return(null); } } return(origins); }
private void _SendSeedMessagesAndWaitForResults(FanoutQueryMessageReader request, int my_transaction, AggregationObject aggregation_obj, List <FanoutPathDescriptor> origin_path_descriptors) { Debug.Assert(origin_path_descriptors.Count != 0); // send the first(seed) search messages out. var grouped_origin_path_descs = from pd in origin_path_descriptors group pd by Global.CloudStorage.GetServerIdByCellId(pd.hop_0); var seed_message_cnt = grouped_origin_path_descs.Count(); var wait_count_per_seed = GetWaitCount(request.maxHop); foreach (var g in grouped_origin_path_descs) { MessageDispatcher.DispatchOriginMessage(g.Key, my_transaction, g); } var quota_stopwatch = Stopwatch.StartNew(); int minimum_nowait_result_count = MinimalRequiredResultCount(request); if (minimum_nowait_result_count == 0) { minimum_nowait_result_count = int.MaxValue; } long waitCount = 0; long waitMax = seed_message_cnt * wait_count_per_seed; for (; waitCount < waitMax; ++waitCount) { var time_left = s_query_time_quota - quota_stopwatch.ElapsedMilliseconds; if (!_QueryTimeoutEnabled()) { aggregation_obj.local_signals.Wait(); } else if (time_left > 0) { if (!aggregation_obj.local_signals.Wait((int)time_left)) { break; } } else /*time out*/ break { ; } if (aggregation_obj.results.Count >= minimum_nowait_result_count) { break; } }
private string GetQueryResultCacheRequestKey(FanoutQueryMessageReader request) { StringBuilder sb = new StringBuilder("request:"); sb.Append(Serializer.ToString(request.origin)); sb.Append(':'); sb.Append(request.originQuery); sb.Append(':'); sb.Append(Serializer.ToString(request.predicates)); sb.Append(':'); sb.Append(Serializer.ToString(request.edge_types)); return(sb.ToString()); }
internal void RegisterQueryResult(int transaction_id, FanoutQueryMessageReader request, AggregationObject aggregation_obj) { if (aggregation_obj.results.Count == 0) { Log.WriteLine(LogLevel.Debug, "QueryResultCache: ignoring empty query result, transaction id = {0}.", transaction_id); return; } QueryResultCacheEntry entry = new QueryResultCacheEntry(transaction_id, aggregation_obj); string key_query = GetQueryResultCacheRequestKey(request); string key_trans = GetQueryResultCacheTransactionKey(entry.transaction_id); m_memory_cache.Set(key_query, entry, m_cache_policy); m_memory_cache.Set(key_trans, entry, m_cache_policy); }
/// <returns>null if no cached query result is found.</returns> internal AggregationObject GetCachedQueryResult(FanoutQueryMessageReader query) { string key = GetQueryResultCacheRequestKey(query); QueryResultCacheEntry entry = (QueryResultCacheEntry)m_memory_cache.Get(key); if (entry == null) { return(null); } int result_cnt = entry.aggregation_obj.results.Count; if (result_cnt < FanoutSearchModule.MinimalRequiredResultCount(query)) { return(null); } Log.WriteLine(LogLevel.Debug, "QueryResultCache: Cache hit."); return(entry.aggregation_obj); }
/// <summary> /// The main query handler. /// </summary> public override void FanoutSearchQueryHandler(FanoutQueryMessageReader request, FanoutResultMessageWriter response) { int my_transaction = -1; List <ResultPathDescriptor> rpaths = null; Stopwatch query_timer = new Stopwatch(); AggregationObject aggregation_obj = null; bool cached = false; int eresult = FanoutSearchErrorCode.OK; //obtain a transaction id atomically using (var _transaction = GetTransactionId(c_master_server_id)) { my_transaction = _transaction.transaction_id; } Log.WriteLine("Transaction #{0} begins.", my_transaction); query_timer.Start(); if (s_cache_enabled) { aggregation_obj = m_cache.GetCachedQueryResult(request); } if (aggregation_obj != null) { cached = true; } else { aggregation_obj = _DoFanoutSearch(my_transaction, request); } if (aggregation_obj == null) { eresult = FanoutSearchErrorCode.Error; } if (aggregation_obj != null && aggregation_obj.timed_out && !s_timeout_return_partial_results) { eresult = FanoutSearchErrorCode.Timeout; aggregation_obj = null; } if (aggregation_obj != null) { rpaths = _PullSelectionsAndAssembleResults(my_transaction, request, aggregation_obj); } else { rpaths = new List <ResultPathDescriptor>(); } response.transaction_id = (aggregation_obj != null) ? my_transaction : eresult; response.paths = rpaths; if (aggregation_obj != null && s_cache_enabled && !aggregation_obj.timed_out) { m_cache.RegisterQueryResult(my_transaction, request, aggregation_obj); } response.metadata_keys.Add("results_pulled_from_cache"); response.metadata_values.Add(cached.ToString()); s_metadataUpdateFunc(request, response); query_timer.Stop(); Log.WriteLine("Transaction #{0} finished. Time = {1}ms.", my_transaction, query_timer.ElapsedMilliseconds); }
private AggregationObject _DoFanoutSearch(int transaction_id, FanoutQueryMessageReader request) { AggregationObject aggregation_obj = null; Stopwatch fanout_timer = new Stopwatch(); bool query_registered = false; do { List <FanoutPathDescriptor> origin_path_descriptors = _GetOriginPathDescriptors(request); fanout_timer.Start(); if (origin_path_descriptors == null) { aggregation_obj = null; break; } // Broadcast initialization message Parallel.For(0, Global.ServerCount, i => { using (var init_msg = new QueryInitializationMessageWriter(request, transaction_id, Global.MyServerID)) { QueryInitialization(i, init_msg); } }); /* From this point on, we cannot abort this query without uninitializing our peers. */ Log.WriteLine(LogLevel.Debug, "Transaction #{0} initialization synchronization complete, time = {1}ms.", transaction_id, fanout_timer.ElapsedMilliseconds); query_registered = m_aggregationObjects.TryGetValue(transaction_id, out aggregation_obj); if (!query_registered) { Log.WriteLine(LogLevel.Error, "Transaction #{0}: Query registration failed.", transaction_id); aggregation_obj = null; break; } // For 0-hop queries, we simply return what we have in origin_path_descriptors if (request.maxHop == 0) { aggregation_obj.results = origin_path_descriptors; break; } _SendSeedMessagesAndWaitForResults(request, transaction_id, aggregation_obj, origin_path_descriptors); } while (false); // Query complete. Clean it up. if (query_registered) { Parallel.For(0, Global.ServerCount, i => { using (var uninit_msg = new TransactionIdMessageWriter(transaction_id)) { QueryUninitialization(i, uninit_msg); } }); } fanout_timer.Stop(); Log.WriteLine("Transaction #{0} Fanout finished. Time = {1}ms.", transaction_id, fanout_timer.ElapsedMilliseconds); return(aggregation_obj); }