protected void Flush(bool continue_only) { IndexerRequest flushed_request; if (continue_only) { // if the request is merely to signal indexhelper to continue indexing, // then sent a fake indexerrequest but then use the previous request to retrieve // deferred indexables flushed_request = new IndexerRequest(); flushed_request.ContinueIndexing = true; // Do not pass this through PreFlushHook since this is a fake request } else { lock (request_lock) { if (pending_request.IsEmpty) { return; } flushed_request = pending_request; pending_request = new IndexerRequest(); // We hold the request_lock when calling PreFlushHook, so // that no other requests can come in until it exits. PreFlushHook(flushed_request); } } IndexerReceipt [] receipts; receipts = indexer.Flush(flushed_request); PostFlushHook(flushed_request, receipts); if (continue_only) { flushed_request = pending_request; } // Silently return if we get a null back. This is probably // a bad thing to do. If IndexHelper is shutdown because of // memory blowup or is crashed, then null is returned. Silently // returning means ignoring the indexables in the IndexHelper's // queue (which could be more than what was sent in the last request, // since there could be some deferred-indexables too). if (receipts == null) { return; } // Nothing happened (except maybe an optimize, which does not // generate a receipt). Also do nothing. if (receipts.Length == 0) { return; } // Update the cached count of items in the driver // FIXME: Verify that this still works after all the deferred-indexable fu driver.SetItemCount(indexer.GetItemCount()); // Something happened, so schedule an optimize just in case. ScheduleOptimize(); if (fa_store != null) { fa_store.BeginTransaction(); } ArrayList added_uris = new ArrayList(); ArrayList removed_uris = new ArrayList(); bool indexer_indexable_receipt = false; for (int i = 0; i < receipts.Length; ++i) { if (receipts [i] is IndexerAddedReceipt) { IndexerAddedReceipt r; r = (IndexerAddedReceipt)receipts [i]; Indexable indexable = flushed_request.RetrieveRequestIndexable(r); if (indexable == null) { Log.Debug("Should not happen! Previously requested indexable with id #{0} has eloped!", r.Id); continue; } // Add the Uri to the list for our change data // *before* doing any post-processing. // This ensures that we have internal uris when // we are remapping. added_uris.Add(indexable.Uri); // Call the appropriate hook Uri notification_uri = indexable.Uri; try { // Map from internal->external Uris in the PostAddHook notification_uri = PostAddHook(indexable, r); } catch (Exception ex) { Logger.Log.Warn(ex, "Caught exception in PostAddHook '{0}' '{1}' '{2}'", indexable.Uri, r.FilterName, r.FilterVersion); } // Every added Uri also needs to be listed as removed, // to avoid duplicate hits in the query. Since the // removed Uris need to be external Uris, we add them // to the list *after* post-processing. removed_uris.Add(notification_uri); } else if (receipts [i] is IndexerRemovedReceipt) { IndexerRemovedReceipt r; r = (IndexerRemovedReceipt)receipts [i]; Indexable indexable = flushed_request.RetrieveRequestIndexable(r); if (indexable == null) // Should never happen { Log.Warn("Unable to match indexable-remove #{0} to any request!", r.Id); continue; } // Call the appropriate hook Uri notification_uri = indexable.Uri; try { notification_uri = PostRemoveHook(indexable, r.NumRemoved); } catch (Exception ex) { Logger.Log.Warn(ex, "Caught exception in PostRemoveHook '{0}'", indexable.Uri); } // If nothing was removed, no need for change notification if (r.NumRemoved <= 0) { continue; } // Add the removed Uri to the list for our // change data. This will be an external Uri // when we are remapping. removed_uris.Add(notification_uri); } else if (receipts [i] is IndexerIndexablesReceipt) { indexer_indexable_receipt = true; } } if (!continue_only) { lock (request_lock) { pending_request.DeferredIndexables = flushed_request.DeferredIndexables; } } if (indexer_indexable_receipt) { Log.Debug("Indexing of indexer generated indexables is paused. Scheduling job to continue."); // Create a task asking the indexer to continue indexing Scheduler.Task task; task = Scheduler.TaskFromHook(new Scheduler.TaskHook(ContinueIndexerIndexableIndexing)); // Schedule it so that it is the immediate next task to be scheduled task.Priority = Scheduler.Priority.Immediate; task.SubPriority = 100; task.Source = this; task.Tag = "Continue indexing generated indexables from " + IndexName; ThisScheduler.Add(task); } if (fa_store != null) { fa_store.CommitTransaction(); } // Propagate the change notification to any open queries. if (added_uris.Count > 0 || removed_uris.Count > 0) { ChangeData change_data; change_data = new ChangeData(); change_data.AddedUris = added_uris; change_data.RemovedUris = removed_uris; QueryDriver.QueryableChanged(this, change_data); } }
// This is mostly a copy of LuceneQueryable.Flush + FSQ.PostAddHooks/PostRemoveHook static bool FlushIndexer(IIndexer indexer) { IndexerRequest flushed_request; if (pending_request.IsEmpty) { return(false); } flushed_request = pending_request; pending_request = new IndexerRequest(); IndexerReceipt [] receipts; receipts = indexer.Flush(flushed_request); // Flush will return null if it encounters a shutdown during flushing if (receipts == null) { return(false); } fa_store.BeginTransaction(); bool indexer_indexable_receipt = false; foreach (IndexerReceipt raw_r in receipts) { if (raw_r is IndexerAddedReceipt) { // Update the file attributes IndexerAddedReceipt r = (IndexerAddedReceipt)raw_r; Indexable indexable = flushed_request.RetrieveRequestIndexable(r); if (indexable == null) { Logger.Log.Debug("Should not happen! Previously requested indexable with id #{0} has eloped!", r.Id); continue; } // We don't need to write out any file attributes for // children. if (indexable.ParentUri != null) { continue; } string path = indexable.Uri.LocalPath; FileAttributes attr; attr = fa_store.ReadOrCreate(path); attr.LastWriteTime = indexable.Timestamp; attr.FilterName = r.FilterName; attr.FilterVersion = r.FilterVersion; fa_store.Write(attr); } else if (raw_r is IndexerRemovedReceipt) { // Update the file attributes IndexerRemovedReceipt r = (IndexerRemovedReceipt)raw_r; Indexable indexable = flushed_request.RetrieveRequestIndexable(r); if (indexable == null) // Should never happen { Log.Warn("Unable to match indexable-remove #{0} to any request!", r.Id); continue; } string path = indexable.Uri.LocalPath; Logger.Log.Debug("Removing: '{0}'", path); fa_store.Drop(path); } else if (raw_r is IndexerIndexablesReceipt) { indexer_indexable_receipt = true; } } pending_request.DeferredIndexables = flushed_request.DeferredIndexables; // Reschedule if some indexable generated more indexables if (indexer_indexable_receipt) { pending_request.ContinueIndexing = true; return(true); } fa_store.CommitTransaction(); return(false); }