internal FrozenBufferedUpdates FreezeGlobalBuffer(DeleteSlice callerSlice)
        {
            globalBufferLock.@Lock();

            /*
             * Here we freeze the global buffer so we need to lock it, apply all
             * deletes in the queue and reset the global slice to let the GC prune the
             * queue.
             */
            Node currentTail = tail; // take the current tail make this local any

            // Changes after this call are applied later
            // and not relevant here
            if (callerSlice != null)
            {
                // Update the callers slices so we are on the same page
                callerSlice.sliceTail = currentTail;
            }
            try
            {
                if (globalSlice.sliceTail != currentTail)
                {
                    globalSlice.sliceTail = currentTail;
                    globalSlice.Apply(globalBufferedUpdates, BufferedUpdates.MAX_INT32);
                }

                FrozenBufferedUpdates packet = new FrozenBufferedUpdates(globalBufferedUpdates, false);
                globalBufferedUpdates.Clear();
                return(packet);
            }
            finally
            {
                globalBufferLock.Unlock();
            }
        }
예제 #2
0
        public DocumentsWriterPerThread(string segmentName, Directory directory, LiveIndexWriterConfig indexWriterConfig, InfoStream infoStream, DocumentsWriterDeleteQueue deleteQueue, FieldInfos.Builder fieldInfos)
        {
            this.directoryOrig       = directory;
            this.directory           = new TrackingDirectoryWrapper(directory);
            this.fieldInfos          = fieldInfos;
            this.indexWriterConfig   = indexWriterConfig;
            this.infoStream          = infoStream;
            this.codec               = indexWriterConfig.Codec;
            this.docState            = new DocState(this, infoStream);
            this.docState.similarity = indexWriterConfig.Similarity;
            bytesUsed          = Counter.NewCounter();
            byteBlockAllocator = new DirectTrackingAllocator(bytesUsed);
            pendingUpdates     = new BufferedUpdates();
            intBlockAllocator  = new Int32BlockAllocator(bytesUsed);
            this.deleteQueue   = deleteQueue;
            if (Debugging.AssertsEnabled)
            {
                Debugging.Assert(numDocsInRAM == 0, "num docs {0}", numDocsInRAM);
            }
            pendingUpdates.Clear();
            deleteSlice = deleteQueue.NewSlice();

            segmentInfo = new SegmentInfo(directoryOrig, Constants.LUCENE_MAIN_VERSION, segmentName, -1, false, codec, null);
            if (Debugging.AssertsEnabled)
            {
                Debugging.Assert(numDocsInRAM == 0);
            }
            if (INFO_VERBOSE && infoStream.IsEnabled("DWPT"))
            {
                infoStream.Message("DWPT", Thread.CurrentThread.Name + " init seg=" + segmentName + " delQueue=" + deleteQueue);
            }
            // this should be the last call in the ctor
            // it really sucks that we need to pull this within the ctor and pass this ref to the chain!
            consumer = indexWriterConfig.IndexingChain.GetChain(this);
        }
 internal bool UpdateSlice(DeleteSlice slice)
 {
     if (slice.sliceTail != tail) // If we are the same just
     {
         slice.sliceTail = tail;
         return(true);
     }
     return(false);
 }
예제 #4
0
 protected internal UpdateThread(DocumentsWriterDeleteQueue queue, AtomicInt32 index, int?[] ids, CountdownEvent latch)
 {
     this.Queue = queue;
     this.Index = index;
     this.Ids   = ids;
     this.Slice = queue.NewSlice();
     Deletes    = new BufferedUpdates();
     this.Latch = latch;
 }
예제 #5
0
 public bool UpdateSlice(DeleteSlice slice)
 {
     if (slice.SliceTail != Tail) // If we are the same just
     {
         slice.SliceTail = Tail;
         return(true);
     }
     return(false);
 }
예제 #6
0
        public virtual void TestUpdateDelteSlices()
        {
            DocumentsWriterDeleteQueue queue = new DocumentsWriterDeleteQueue();
            int size = 200 + Random.Next(500) * RANDOM_MULTIPLIER;

            int?[] ids = new int?[size];
            for (int i = 0; i < ids.Length; i++)
            {
                ids[i] = Random.Next();
            }
            DeleteSlice     slice1       = queue.NewSlice();
            DeleteSlice     slice2       = queue.NewSlice();
            BufferedUpdates bd1          = new BufferedUpdates();
            BufferedUpdates bd2          = new BufferedUpdates();
            int             last1        = 0;
            int             last2        = 0;
            ISet <Term>     uniqueValues = new JCG.HashSet <Term>();

            for (int j = 0; j < ids.Length; j++)
            {
                int?i = ids[j];
                // create an array here since we compare identity below against tailItem
                Term[] term = new Term[] { new Term("id", i.ToString()) };
                uniqueValues.Add(term[0]);
                queue.AddDelete(term);
                if (Random.Next(20) == 0 || j == ids.Length - 1)
                {
                    queue.UpdateSlice(slice1);
                    Assert.IsTrue(slice1.IsTailItem(term));
                    slice1.Apply(bd1, j);
                    AssertAllBetween(last1, j, bd1, ids);
                    last1 = j + 1;
                }
                if (Random.Next(10) == 5 || j == ids.Length - 1)
                {
                    queue.UpdateSlice(slice2);
                    Assert.IsTrue(slice2.IsTailItem(term));
                    slice2.Apply(bd2, j);
                    AssertAllBetween(last2, j, bd2, ids);
                    last2 = j + 1;
                }
                Assert.AreEqual(j + 1, queue.NumGlobalTermDeletes);
            }
            assertEquals(uniqueValues, new JCG.HashSet <Term>(bd1.terms.Keys));
            assertEquals(uniqueValues, new JCG.HashSet <Term>(bd2.terms.Keys));
            var frozenSet = new JCG.HashSet <Term>();

            foreach (Term t in queue.FreezeGlobalBuffer(null).GetTermsEnumerable())
            {
                BytesRef bytesRef = new BytesRef();
                bytesRef.CopyBytes(t.Bytes);
                frozenSet.Add(new Term(t.Field, bytesRef));
            }
            assertEquals(uniqueValues, frozenSet);
            Assert.AreEqual(0, queue.NumGlobalTermDeletes, "num deletes must be 0 after freeze");
        }
        internal DocumentsWriterDeleteQueue(BufferedUpdates globalBufferedUpdates, long generation)
        {
            this.globalBufferedUpdates = globalBufferedUpdates;
            this.generation            = generation;

            /*
             * we use a sentinel instance as our initial tail. No slice will ever try to
             * apply this tail since the head is always omitted.
             */
            tail        = new Node(null); // sentinel
            globalSlice = new DeleteSlice(tail);
        }
예제 #8
0
        public virtual void TestStressDeleteQueue()
        {
            DocumentsWriterDeleteQueue queue = new DocumentsWriterDeleteQueue();
            ISet <Term> uniqueValues         = new JCG.HashSet <Term>();
            int         size = 10000 + Random.Next(500) * RANDOM_MULTIPLIER;

            int?[] ids = new int?[size];
            for (int i = 0; i < ids.Length; i++)
            {
                ids[i] = Random.Next();
                uniqueValues.Add(new Term("id", ids[i].ToString()));
            }
            CountdownEvent latch      = new CountdownEvent(1);
            AtomicInt32    index      = new AtomicInt32(0);
            int            numThreads = 2 + Random.Next(5);

            UpdateThread[] threads = new UpdateThread[numThreads];
            for (int i = 0; i < threads.Length; i++)
            {
                threads[i] = new UpdateThread(queue, index, ids, latch);
                threads[i].Start();
            }
            latch.Signal();
            for (int i = 0; i < threads.Length; i++)
            {
                threads[i].Join();
            }

            foreach (UpdateThread updateThread in threads)
            {
                DeleteSlice slice = updateThread.Slice;
                queue.UpdateSlice(slice);
                BufferedUpdates deletes = updateThread.Deletes;
                slice.Apply(deletes, BufferedUpdates.MAX_INT32);
                assertEquals(uniqueValues, new JCG.HashSet <Term>(deletes.terms.Keys));
            }
            queue.TryApplyGlobalSlice();
            ISet <Term> frozenSet = new JCG.HashSet <Term>();

            foreach (Term t in queue.FreezeGlobalBuffer(null).GetTermsEnumerable())
            {
                BytesRef bytesRef = new BytesRef();
                bytesRef.CopyBytes(t.Bytes);
                frozenSet.Add(new Term(t.Field, bytesRef));
            }
            Assert.AreEqual(0, queue.NumGlobalTermDeletes, "num deletes must be 0 after freeze");
            Assert.AreEqual(uniqueValues.Count, frozenSet.Count);
            assertEquals(uniqueValues, frozenSet);
        }
        /// <summary>
        /// invariant for document update
        /// </summary>
        internal void Add(Term term, DeleteSlice slice)
        {
            TermNode termNode = new TermNode(term);

            Add(termNode);

            /*
             * this is an update request where the term is the updated documents
             * delTerm. in that case we need to guarantee that this insert is atomic
             * with regards to the given delete slice. this means if two threads try to
             * update the same document with in turn the same delTerm one of them must
             * win. By taking the node we have created for our del term as the new tail
             * it is guaranteed that if another thread adds the same right after us we
             * will apply this delete next time we update our slice and one of the two
             * competing updates wins!
             */
            slice.sliceTail = termNode;
            Debug.Assert(slice.sliceHead != slice.sliceTail, "slice head and tail must differ after add");
            TryApplyGlobalSlice(); // TODO doing this each time is not necessary maybe
            // we can do it just every n times or so?
        }
 protected internal UpdateThread(DocumentsWriterDeleteQueue queue, AtomicInteger index, int?[] ids, CountDownLatch latch)
 {
     this.Queue = queue;
     this.Index = index;
     this.Ids = ids;
     this.Slice = queue.NewSlice();
     Deletes = new BufferedUpdates();
     this.Latch = latch;
 }
 public DocumentsWriterDeleteQueue(BufferedUpdates globalBufferedUpdates, long generation)
 {
     this.GlobalBufferedUpdates = globalBufferedUpdates;
     this.Generation = generation;
     /*
      * we use a sentinel instance as our initial tail. No slice will ever try to
      * apply this tail since the head is always omitted.
      */
     Tail = new Node(null); // sentinel
     GlobalSlice = new DeleteSlice(Tail);
 }
 public bool UpdateSlice(DeleteSlice slice)
 {
     if (slice.SliceTail != Tail) // If we are the same just
     {
         slice.SliceTail = Tail;
         return true;
     }
     return false;
 }
        public FrozenBufferedUpdates FreezeGlobalBuffer(DeleteSlice callerSlice)
        {
            GlobalBufferLock.@Lock();
            /*
             * Here we freeze the global buffer so we need to lock it, apply all
             * deletes in the queue and reset the global slice to let the GC prune the
             * queue.
             */
            Node currentTail = Tail; // take the current tail make this local any
            // Changes after this call are applied later
            // and not relevant here
            if (callerSlice != null)
            {
                // Update the callers slices so we are on the same page
                callerSlice.SliceTail = currentTail;
            }
            try
            {
                if (GlobalSlice.SliceTail != currentTail)
                {
                    GlobalSlice.SliceTail = currentTail;
                    GlobalSlice.Apply(GlobalBufferedUpdates, BufferedUpdates.MAX_INT);
                }

                FrozenBufferedUpdates packet = new FrozenBufferedUpdates(GlobalBufferedUpdates, false);
                GlobalBufferedUpdates.Clear();
                return packet;
            }
            finally
            {
                GlobalBufferLock.Unlock();
            }
        }
 /// <summary>
 /// invariant for document update
 /// </summary>
 public void Add(Term term, DeleteSlice slice)
 {
     TermNode termNode = new TermNode(term);
     Add(termNode);
     /*
      * this is an update request where the term is the updated documents
      * delTerm. in that case we need to guarantee that this insert is atomic
      * with regards to the given delete slice. this means if two threads try to
      * update the same document with in turn the same delTerm one of them must
      * win. By taking the node we have created for our del term as the new tail
      * it is guaranteed that if another thread adds the same right after us we
      * will apply this delete next time we update our slice and one of the two
      * competing updates wins!
      */
     slice.SliceTail = termNode;
     Debug.Assert(slice.SliceHead != slice.SliceTail, "slice head and tail must differ after add");
     TryApplyGlobalSlice(); // TODO doing this each time is not necessary maybe
     // we can do it just every n times or so?
 }