/// <summary>
        ///
        /// </summary>
        /// <param name="ignore">Ignored, used to keep the delegate signature that WaitCallback requires</param>
        public void Run(object ignore)
        {
            Workspace    workspace = new Workspace(searchFactoryImplementor);
            LuceneWorker worker    = new LuceneWorker(workspace);

            try
            {
                List <LuceneWorker.WorkWithPayload> queueWithFlatDPs = new List <LuceneWorker.WorkWithPayload>(queue.Count * 2);
                foreach (LuceneWork work in queue)
                {
                    DocumentBuilder        documentBuilder  = searchFactoryImplementor.DocumentBuilders[work.EntityClass];
                    IIndexShardingStrategy shardingStrategy = documentBuilder.DirectoryProvidersSelectionStrategy;
                    if (work is PurgeAllLuceneWork)
                    {
                        IDirectoryProvider[] providers = shardingStrategy.GetDirectoryProvidersForDeletion(work.EntityClass, work.Id, work.IdInString);
                        foreach (IDirectoryProvider provider in providers)
                        {
                            queueWithFlatDPs.Add(new LuceneWorker.WorkWithPayload(work, provider));
                        }
                    }
                    else if (work is AddLuceneWork)
                    {
                        IDirectoryProvider provider = shardingStrategy.GetDirectoryProviderForAddition(work.EntityClass, work.Id, work.IdInString, work.Document);
                        queueWithFlatDPs.Add(new LuceneWorker.WorkWithPayload(work, provider));
                    }
                    else if (work is DeleteLuceneWork)
                    {
                        IDirectoryProvider[] providers = shardingStrategy.GetDirectoryProvidersForDeletion(work.EntityClass, work.Id, work.IdInString);
                        foreach (IDirectoryProvider provider in providers)
                        {
                            queueWithFlatDPs.Add(new LuceneWorker.WorkWithPayload(work, provider));
                        }
                    }
                    else if (work is OptimizeLuceneWork)
                    {
                        IDirectoryProvider[] providers = shardingStrategy.GetDirectoryProvidersForAllShards();
                        foreach (IDirectoryProvider provider in providers)
                        {
                            queueWithFlatDPs.Add(new LuceneWorker.WorkWithPayload(work, provider));
                        }
                    }
                    else
                    {
                        throw new AssertionFailure("Unknown work type: " + work.GetType());
                    }
                }

                DeadLockFreeQueue(queueWithFlatDPs);
                CheckForBatchIndexing(workspace);
                foreach (LuceneWorker.WorkWithPayload luceneWork in queueWithFlatDPs)
                {
                    worker.PerformWork(luceneWork);
                }
            }
            finally
            {
                workspace.Dispose();
                queue.Clear();
            }
        }
        public void PurgeAll()
        {
            using (ISession s = OpenSession())
            {
                SearchFactoryImpl searchFactory = SearchFactoryImpl.GetSearchFactory(cfg);
                System.Type targetType = typeof(Document);
                IDirectoryProvider provider = searchFactory.GetDirectoryProviders(targetType)[0];
                Workspace workspace = new Workspace(searchFactory);

                using (ITransaction tx = s.BeginTransaction())
                {
                    Document doc = new Document("Hibernate in Action", "Object and Relational", "blah blah blah");
                    searchFactory.PerformWork(doc, 1, s, WorkType.Add);
                    doc = new Document("Object and Relational", "Hibernate in Action", "blah blah blah");
                    searchFactory.PerformWork(doc, 2, s, WorkType.Add);
                    tx.Commit();
                }
                Assert.AreEqual(2, workspace.GetIndexReader(provider, targetType).NumDocs(), "Documents created");

                using (ITransaction tx = s.BeginTransaction())
                {
                    LuceneWorker luceneWorker = new LuceneWorker(workspace);
                    luceneWorker.PerformWork(new PurgeAllLuceneWork(targetType), provider);
                }
                Assert.AreEqual(0, workspace.GetIndexReader(provider, targetType).NumDocs(), "Document purgation");
            }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="ignore">Ignored, used to keep the delegate signature that WaitCallback requires</param>
        public void Run(object ignore)
        {
            Workspace workspace = new Workspace(searchFactoryImplementor);
            LuceneWorker worker = new LuceneWorker(workspace);
            try
            {
                List<LuceneWorker.WorkWithPayload> queueWithFlatDPs = new List<LuceneWorker.WorkWithPayload>(queue.Count*2);
                foreach (LuceneWork work in queue)
                {
                    DocumentBuilder documentBuilder = searchFactoryImplementor.DocumentBuilders[work.EntityClass];
                    IIndexShardingStrategy shardingStrategy = documentBuilder.DirectoryProvidersSelectionStrategy;
                    if (work is PurgeAllLuceneWork)
                    {
                        IDirectoryProvider[] providers = shardingStrategy.GetDirectoryProvidersForDeletion(work.EntityClass, work.Id, work.IdInString);
                        foreach (IDirectoryProvider provider in providers)
                        {
                            queueWithFlatDPs.Add(new LuceneWorker.WorkWithPayload(work, provider));
                        }
                    }
                    else if (work is AddLuceneWork)
                    {
                        IDirectoryProvider provider = shardingStrategy.GetDirectoryProviderForAddition(work.EntityClass, work.Id, work.IdInString, work.Document);
                        queueWithFlatDPs.Add(new LuceneWorker.WorkWithPayload(work, provider));
                    }
                    else if (work is DeleteLuceneWork)
                    {
                        IDirectoryProvider[] providers = shardingStrategy.GetDirectoryProvidersForDeletion(work.EntityClass, work.Id, work.IdInString);
                        foreach (IDirectoryProvider provider in providers)
                        {
                            queueWithFlatDPs.Add(new LuceneWorker.WorkWithPayload(work, provider));
                        }
                    }
                    else if (work is OptimizeLuceneWork)
                    {
                        IDirectoryProvider[] providers = shardingStrategy.GetDirectoryProvidersForAllShards();
                        foreach (IDirectoryProvider provider in providers)
                        {
                            queueWithFlatDPs.Add(new LuceneWorker.WorkWithPayload(work, provider));
                        }
                    }
                    else
                    {
                        throw new AssertionFailure("Unknown work type: " + work.GetType());
                    }
                }

                DeadLockFreeQueue(queueWithFlatDPs);
                CheckForBatchIndexing(workspace);
                foreach (LuceneWorker.WorkWithPayload luceneWork in queueWithFlatDPs)
                {
                    worker.PerformWork(luceneWork);
                }
            }
            finally
            {
                workspace.Dispose();
                queue.Clear();
            }
        }
        private static long GetWorkHashCode(LuceneWorker.WorkWithPayload luceneWork)
        {
            IDirectoryProvider provider = luceneWork.Provider;
            int h = provider.GetType().GetHashCode();
            h = (31 * h) + provider.GetHashCode();
            long extendedHash = h; // to be sure extendedHash + 1 < extendedHash + 2 is always true
            if (luceneWork.Work is AddLuceneWork)
            {
                extendedHash += 1; // addwork after deleteWork
            }

            if (luceneWork.Work is OptimizeLuceneWork)
            {
                extendedHash += 2; // optimize after everything
            }

            return extendedHash;
        }