indexmerger.java

来自「jsr170接口的java实现。是个apache的开源项目。」· Java 代码 · 共 500 行 · 第 1/2 页

JAVA
500
字号
/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements.  See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License.  You may obtain a copy of the License at * *      http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */package org.apache.jackrabbit.core.query.lucene;import org.apache.lucene.index.Term;import org.apache.lucene.index.IndexReader;import org.apache.commons.collections.Buffer;import org.apache.commons.collections.BufferUtils;import org.apache.commons.collections.buffer.UnboundedFifoBuffer;import org.slf4j.Logger;import org.slf4j.LoggerFactory;import java.util.List;import java.util.Collections;import java.util.ArrayList;import java.util.Iterator;import java.io.IOException;import EDU.oswego.cs.dl.util.concurrent.Sync;import EDU.oswego.cs.dl.util.concurrent.Mutex;/** * Merges indexes in a separate deamon thread. */class IndexMerger extends Thread implements IndexListener {    /**     * Logger instance for this class.     */    private static final Logger log = LoggerFactory.getLogger(IndexMerger.class);    /**     * Marker task to signal the background thread to quit.     */    private static final Merge QUIT = new Merge(new Index[0]);    /**     * minMergeDocs config parameter.     */    private int minMergeDocs = SearchIndex.DEFAULT_MIN_MERGE_DOCS;    /**     * maxMergeDocs config parameter     */    private int maxMergeDocs = SearchIndex.DEFAULT_MAX_MERGE_DOCS;    /**     * mergeFactor config parameter     */    private int mergeFactor = SearchIndex.DEFAULT_MERGE_FACTOR;    /**     * Queue of merge Tasks     */    private final Buffer mergeTasks = BufferUtils.blockingBuffer(new UnboundedFifoBuffer());    /**     * List of id <code>Term</code> that identify documents that were deleted     * while a merge was running.     */    private final List deletedDocuments = Collections.synchronizedList(new ArrayList());    /**     * List of <code>IndexBucket</code>s in ascending document limit.     */    private final List indexBuckets = new ArrayList();    /**     * The <code>MultiIndex</code> this index merger is working on.     */    private final MultiIndex multiIndex;    /**     * Monitor object to synchronize merge calculation.     */    private final Object lock = new Object();    /**     * Mutex that is acquired when replacing indexes on MultiIndex.     */    private final Sync indexReplacement = new Mutex();    /**     * When released, indicates that this index merger is idle.     */    private final Sync mergerIdle = new Mutex();    /**     * Creates an <code>IndexMerger</code>.     *     * @param multiIndex the <code>MultiIndex</code>.     */    IndexMerger(MultiIndex multiIndex) {        this.multiIndex = multiIndex;        setName("IndexMerger");        setDaemon(true);        try {            mergerIdle.acquire();        } catch (InterruptedException e) {            // will never happen, lock is free upon construction            throw new InternalError("Unable to acquire mutex after construction");        }    }    /**     * Informs the index merger that an index was added / created.     *     * @param name the name of the index.     * @param numDocs the number of documents it contains.     */    void indexAdded(String name, int numDocs) {        if (numDocs < 0) {            throw new IllegalArgumentException("numDocs must be positive");        }        // multiple threads may enter this method:        // - the background thread of this IndexMerger, when it replaces indexes        //   after a successful merge        // - a regular thread that updates the workspace        //        // therefore we have to synchronize this block        synchronized (lock) {            // initially create buckets            if (indexBuckets.size() == 0) {                int lower = 0;                int upper = minMergeDocs;                while (upper < maxMergeDocs) {                    indexBuckets.add(new IndexBucket(lower, upper, true));                    lower = upper + 1;                    upper *= mergeFactor;                }                // one with upper = maxMergeDocs                indexBuckets.add(new IndexBucket(lower, maxMergeDocs, false));                // and another one as overflow, just in case...                indexBuckets.add(new IndexBucket(maxMergeDocs + 1, Integer.MAX_VALUE, false));            }            // put index in bucket            IndexBucket bucket = (IndexBucket) indexBuckets.get(indexBuckets.size() - 1);            for (int i = 0; i < indexBuckets.size(); i++) {                bucket = (IndexBucket) indexBuckets.get(i);                if (bucket.fits(numDocs)) {                    break;                }            }            bucket.add(new Index(name, numDocs));            if (log.isDebugEnabled()) {                log.debug("index added: name=" + name + ", numDocs=" + numDocs);            }            // if bucket does not allow merge, we don't have to continue            if (!bucket.allowsMerge()) {                return;            }            // check if we need a merge            if (bucket.size() >= mergeFactor) {                long targetMergeDocs = bucket.upper;                targetMergeDocs = Math.min(targetMergeDocs * mergeFactor, maxMergeDocs);                // sum up docs in bucket                List indexesToMerge = new ArrayList();                int mergeDocs = 0;                for (Iterator it = bucket.iterator(); it.hasNext() && mergeDocs <= targetMergeDocs;) {                    indexesToMerge.add(it.next());                }                if (indexesToMerge.size() > 2) {                    // found merge                    Index[] idxs = (Index[]) indexesToMerge.toArray(new Index[indexesToMerge.size()]);                    bucket.removeAll(indexesToMerge);                    if (log.isDebugEnabled()) {                        log.debug("requesting merge for " + indexesToMerge);                    }                    mergeTasks.add(new Merge(idxs));                    log.debug("merge queue now contains " + mergeTasks.size() + " tasks.");                }            }        }    }    /**     * @inheritDoc     */    public void documentDeleted(Term id) {        log.debug("document deleted: " + id.text());        deletedDocuments.add(id);    }    /**     * When the calling thread returns this index merger will be idle, that is     * there will be no merge tasks pending anymore. The method returns immediately     * if there are currently no tasks pending at all.     */    void waitUntilIdle() throws InterruptedException {        mergerIdle.acquire();        // and immediately release again        mergerIdle.release();    }    /**     * Signals this <code>IndexMerger</code> to stop and waits until it     * has terminated.     */    void dispose() {        log.debug("dispose IndexMerger");        // get mutex for index replacements        try {            indexReplacement.acquire();        } catch (InterruptedException e) {            log.warn("Interrupted while acquiring index replacement sync: " + e);            // try to stop IndexMerger without the sync        }        // clear task queue        mergeTasks.clear();        // send quit        mergeTasks.add(QUIT);        log.debug("quit sent");        try {            // give the merger thread some time to quit,            // it is possible that the merger is busy working on a large index.            // if that is the case we will just ignore it and the deamon will            // die without being able to finish the merge.            // at this point it is not possible anymore to replace indexes            // on the MultiIndex because we hold the indexReplacement Sync.            this.join(500);            if (isAlive()) {                log.info("Unable to stop IndexMerger. Deamon is busy.");            } else {                log.debug("IndexMerger thread stopped");            }            log.debug("merge queue size: " + mergeTasks.size());        } catch (InterruptedException e) {            log.warn("Interrupted while waiting for IndexMerger thread to terminate.");        }

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?