/// <summary>
        /// Constructor with the given index directory and callback to notify when the indexes were updated.
        /// </summary>
        /// <exception cref="System.IO.IOException"></exception>
        public IndexAndTaxonomyReplicationHandler(Directory indexDirectory, Directory taxonomyDirectory, Func <bool?> callback)
        {
            this.indexDirectory    = indexDirectory;
            this.taxonomyDirectory = taxonomyDirectory;
            this.callback          = callback;

            currentVersion       = null;
            currentRevisionFiles = null;

            bool indexExists    = DirectoryReader.IndexExists(indexDirectory);
            bool taxonomyExists = DirectoryReader.IndexExists(taxonomyDirectory);

            if (indexExists != taxonomyExists)
            {
                throw new InvalidOperationException(string.Format("search and taxonomy indexes must either both exist or not: index={0} taxo={1}", indexExists, taxonomyExists));
            }

            if (indexExists)
            {
                IndexCommit indexCommit    = IndexReplicationHandler.GetLastCommit(indexDirectory);
                IndexCommit taxonomyCommit = IndexReplicationHandler.GetLastCommit(taxonomyDirectory);

                currentRevisionFiles = IndexAndTaxonomyRevision.RevisionFiles(indexCommit, taxonomyCommit);
                currentVersion       = IndexAndTaxonomyRevision.RevisionVersion(indexCommit, taxonomyCommit);

                WriteToInfoStream(
                    string.Format("constructor(): currentVersion={0} currentRevisionFiles={1}", currentVersion, currentRevisionFiles),
                    string.Format("constructor(): indexCommit={0} taxoCommit={1}", indexCommit, taxonomyCommit));
            }
        }
        public virtual void RevisionReady(string version,
                                          IDictionary <string, IList <RevisionFile> > revisionFiles,
                                          IDictionary <string, IList <string> > copiedFiles,
                                          IDictionary <string, Directory> sourceDirectory)
        {
            Directory      taxonomyClientDirectory = sourceDirectory[IndexAndTaxonomyRevision.TAXONOMY_SOURCE];
            Directory      indexClientDirectory    = sourceDirectory[IndexAndTaxonomyRevision.INDEX_SOURCE];
            IList <string> taxonomyFiles           = copiedFiles[IndexAndTaxonomyRevision.TAXONOMY_SOURCE];
            IList <string> indexFiles           = copiedFiles[IndexAndTaxonomyRevision.INDEX_SOURCE];
            string         taxonomySegmentsFile = IndexReplicationHandler.GetSegmentsFile(taxonomyFiles, true);
            string         indexSegmentsFile    = IndexReplicationHandler.GetSegmentsFile(indexFiles, false);

            bool success = false;

            try
            {
                // copy taxonomy files before index files
                IndexReplicationHandler.CopyFiles(taxonomyClientDirectory, taxonomyDirectory, taxonomyFiles);
                IndexReplicationHandler.CopyFiles(indexClientDirectory, indexDirectory, indexFiles);

                // fsync all copied files (except segmentsFile)
                if (taxonomyFiles.Any())
                {
                    taxonomyDirectory.Sync(taxonomyFiles);
                }
                indexDirectory.Sync(indexFiles);

                // now copy and fsync segmentsFile, taxonomy first because it is ok if a
                // reader sees a more advanced taxonomy than the index.
                if (taxonomySegmentsFile != null)
                {
                    taxonomyClientDirectory.Copy(taxonomyDirectory, taxonomySegmentsFile, taxonomySegmentsFile, IOContext.READ_ONCE);
                }
                indexClientDirectory.Copy(indexDirectory, indexSegmentsFile, indexSegmentsFile, IOContext.READ_ONCE);

                if (taxonomySegmentsFile != null)
                {
                    taxonomyDirectory.Sync(new[] { taxonomySegmentsFile });
                }
                indexDirectory.Sync(new[] { indexSegmentsFile });

                success = true;
            }
            finally
            {
                if (!success)
                {
                    taxonomyFiles.Add(taxonomySegmentsFile); // add it back so it gets deleted too
                    IndexReplicationHandler.CleanupFilesOnFailure(taxonomyDirectory, taxonomyFiles);
                    indexFiles.Add(indexSegmentsFile);       // add it back so it gets deleted too
                    IndexReplicationHandler.CleanupFilesOnFailure(indexDirectory, indexFiles);
                }
            }

            // all files have been successfully copied + sync'd. update the handler's state
            currentRevisionFiles = revisionFiles;
            currentVersion       = version;

            WriteToInfoStream("revisionReady(): currentVersion=" + currentVersion + " currentRevisionFiles=" + currentRevisionFiles);

            // update the segments.gen file
            IndexReplicationHandler.WriteSegmentsGen(taxonomySegmentsFile, taxonomyDirectory);
            IndexReplicationHandler.WriteSegmentsGen(indexSegmentsFile, indexDirectory);

            // Cleanup the index directory from old and unused index files.
            // NOTE: we don't use IndexWriter.deleteUnusedFiles here since it may have
            // side-effects, e.g. if it hits sudden IO errors while opening the index
            // (and can end up deleting the entire index). It is not our job to protect
            // against those errors, app will probably hit them elsewhere.
            IndexReplicationHandler.CleanupOldIndexFiles(indexDirectory, indexSegmentsFile);
            IndexReplicationHandler.CleanupOldIndexFiles(taxonomyDirectory, taxonomySegmentsFile);

            // successfully updated the index, notify the callback that the index is
            // ready.
            if (callback != null)
            {
                try {
                    callback.Invoke();
                } catch (Exception e) {
                    throw new IOException(e.Message, e);
                }
            }
        }