org.xcmis.search.lucene.index.ReducibleInMemoryIndexDataKeeper.java Source code

Java tutorial

Introduction

Here is the source code for org.xcmis.search.lucene.index.ReducibleInMemoryIndexDataKeeper.java

Source

/*
 * Copyright (C) 2009 eXo Platform SAS.
 *
 * This is free software; you can redistribute it and/or modify it
 * under the terms of the GNU Lesser General Public License as
 * published by the Free Software Foundation; either version 2.1 of
 * the License, or (at your option) any later version.
 *
 * This software is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this software; if not, write to the Free
 * Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
 * 02110-1301 USA, or see the FSF site: http://www.fsf.org.
 */
package org.xcmis.search.lucene.index;

import org.apache.lucene.analysis.SimpleAnalyzer;
import org.apache.lucene.analysis.standard.StandardAnalyzer;
import org.apache.lucene.document.Document;
import org.apache.lucene.index.CorruptIndexException;
import org.apache.lucene.index.IndexReader;
import org.apache.lucene.index.IndexWriter;
import org.apache.lucene.index.SerialMergeScheduler;
import org.apache.lucene.index.Term;
import org.apache.lucene.index.IndexWriter.MaxFieldLength;
import org.apache.lucene.store.Directory;
import org.apache.lucene.store.LockObtainFailedException;
import org.apache.lucene.store.RAMDirectory;
import org.xcmis.spi.utils.Logger;

import java.io.IOException;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;

/**
 * Created by The eXo Platform SAS.
 * 
 * @author <a href="mailto:Sergey.Kabashnyuk@gmail.com">Sergey Kabashnyuk</a>
 * @version $Id: ReducibleInMemoryIndexDataKeeper.java 2 2010-02-04 17:21:49Z andrew00x $
 */
public class ReducibleInMemoryIndexDataKeeper implements TransactionableLuceneIndexDataManager {
    /**
     * Class logger.g
     */
    private static final Logger LOG = Logger.getLogger(ReducibleInMemoryIndexDataKeeper.class);

    /**
     * Index storage.
     */
    public final RAMDirectory indexDirectiry;

    public long lastModifedTime;

    /**
     * pending committed flag
     */
    boolean isPendingCommited;

    /**
     * Started flag.
     */
    boolean isStarted;

    /**
     * Stopped flag.
     */
    boolean isStoped;

    /**
     * Documents map
     */
    private final Map<String, Document> documentsBuffer;

    /**
     * Index storage.
     */
    private IndexReader indexReader;

    /**
     * Pending document buffer.
     */
    private final Map<String, Document> pendingDocumentsBuffer;

    /**
     * Data keeper transaction log.
     */
    private final TransactionLog transactionLog;

    /**
     * @param changes
     * @throws IndexException
     */
    public ReducibleInMemoryIndexDataKeeper(final LoggedIndexTransaction<Document> changes) throws IndexException {
        // this.changes = changes;
        this.indexDirectiry = new RAMDirectory();
        this.transactionLog = changes.getTransactionLog();
        this.isStarted = false;
        this.isPendingCommited = false;
        this.lastModifedTime = System.currentTimeMillis();

        this.documentsBuffer = new HashMap<String, Document>(changes.getAddedDocuments());
        this.pendingDocumentsBuffer = new HashMap<String, Document>(changes.getAddedDocuments());
        initDirectory();
    }

    public ReducibleInMemoryIndexDataKeeper(final RAMDirectory indexDirectiry,
            final Map<String, Document> documentsBuffer, final Map<String, Document> pendingDocumentsBuffer,
            final TransactionLog transactionLog) {
        this.indexDirectiry = indexDirectiry;
        this.documentsBuffer = documentsBuffer;
        this.pendingDocumentsBuffer = pendingDocumentsBuffer;
        this.transactionLog = transactionLog;
        this.isStarted = false;
        // this.changes = null;
        this.isPendingCommited = pendingDocumentsBuffer.size() == 0;
        this.lastModifedTime = System.currentTimeMillis();
    }

    /**
     * @return
     * @throws IndexException
     */
    public Directory getDirectory() throws IndexException {
        if (!isPendingCommited) {
            commitPending();
        }
        return indexDirectiry;
    }

    /**
     * {@inheritDoc}
     */
    public long getDirectorySize(final boolean includeInherited) {

        return this.indexDirectiry.sizeInBytes();
    }

    /**
     * {@inheritDoc}
     */
    public Document getDocument(final String uuid) throws IndexException {
        return this.documentsBuffer.get(uuid);
    }

    /**
     * @return the documentsCount
     */
    public long getDocumentCount() {
        return this.documentsBuffer.size();
    }

    /**
     * @return the documentsUuids
     */
    public Map<String, Document> getDocumentsBuffer() {
        return this.documentsBuffer;
    }

    /**
     * {@inheritDoc}
     * 
     * @throws IndexException
     */
    public IndexReader getIndexReader() throws IndexException {
        // TODO check is stated;
        if (this.documentsBuffer.size() < 1) {
            return null;
        }
        if (!this.isPendingCommited) {
            this.commitPending();
        }
        try {
            if (this.indexReader == null) {
                this.indexReader = IndexReader.open(this.indexDirectiry);
            } else if (!this.indexReader.isCurrent()) {
                this.indexReader = this.indexReader.reopen();
            }
        } catch (final CorruptIndexException e) {
            throw new IndexException(e.getLocalizedMessage(), e);
        } catch (final IOException e) {
            // e.printStackTrace()
            throw new IndexException(e.getLocalizedMessage(), e);
        }
        return this.indexReader;
    }

    public long getLastModifedTime() {
        return this.lastModifedTime;
    }

    /**
     * @return the pendingDocumentsBuffer
     */
    public Map<String, Document> getPendingDocumentsBuffer() {
        return this.pendingDocumentsBuffer;
    }

    /**
     * {@inheritDoc}
     */
    public TransactionLog getTransactionLog() {
        return this.transactionLog;
    }

    /**
     * @return the isPendingCommited
     */
    public boolean isPendingCommited() {
        return this.isPendingCommited;
    }

    /**
     * @return the isStarted
     */
    public boolean isStarted() {
        return this.isStarted;
    }

    /**
     * @return the isStoped
     */
    public boolean isStoped() {
        return this.isStoped;
    }

    /**
     * {@inheritDoc}
     */
    public IndexTransactionModificationReport save(final IndexTransaction<Document> changes)
            throws IndexException, IndexTransactionException {
        // Accepting only deletes , and removing for updates.
        final Set<String> addedDocuments = new HashSet<String>();
        final Set<String> removedDocuments = new HashSet<String>();
        final Set<String> updatedDocuments = new HashSet<String>();

        try {
            // index already started
            synchronized (indexDirectiry) {
                final Set<String> removed = changes.getRemovedDocuments();
                // int numDoc = 0;
                IndexWriter writer = null;
                for (final String removedUuid : removed) {

                    if (this.documentsBuffer.remove(removedUuid) != null) {

                        removedDocuments.add(removedUuid);
                        if (this.isPendingCommited || this.pendingDocumentsBuffer.remove(removedUuid) == null) {
                            if (writer == null) {
                                writer = new IndexWriter(this.indexDirectiry, new StandardAnalyzer(),
                                        MaxFieldLength.UNLIMITED);
                                //to avoid deadlock
                                writer.setMergeScheduler(new SerialMergeScheduler());
                            }
                            writer.deleteDocuments(new Term(FieldNames.UUID, removedUuid));
                        }
                    }

                }

                if (writer != null) {
                    writer.commit();
                    writer.close();
                    this.lastModifedTime = System.currentTimeMillis();
                }
            }

        } catch (final CorruptIndexException e) {
            throw new IndexException(e.getLocalizedMessage(), e);
        } catch (final IOException e) {
            throw new IndexException(e.getLocalizedMessage(), e);
        }

        return new IndexTransactionModificationReportImpl(addedDocuments, removedDocuments, updatedDocuments);
    }

    /**
     * {@inheritDoc}
     * 
     * @throws IndexException
     */
    public void start() throws IndexException {
        this.isStarted = true;

    }

    /**
     * {@inheritDoc}
     * 
     * @throws IndexException
     */
    public void stop() throws IndexException {
        this.indexDirectiry.close();
        this.isStoped = true;
    }

    /**
     * @throws CorruptIndexException
     * @throws LockObtainFailedException
     * @throws IOException
     */
    private void commitPending() throws IndexException {
        IndexWriter writer = null;
        try {
            if (this.pendingDocumentsBuffer.size() > 0) {
                synchronized (this.indexDirectiry) {

                    writer = new IndexWriter(this.indexDirectiry, new StandardAnalyzer(), MaxFieldLength.UNLIMITED);
                    for (final Entry<String, Document> addedDocument : this.pendingDocumentsBuffer.entrySet()) {
                        writer.addDocument(addedDocument.getValue());

                    }
                    this.pendingDocumentsBuffer.clear();
                    // write changes
                    writer.commit();
                    this.isPendingCommited = true;
                    writer.close();
                }
            }
        } catch (final CorruptIndexException e) {
            throw new IndexException(e.getLocalizedMessage(), e);
        } catch (final LockObtainFailedException e) {
            throw new IndexException(e.getLocalizedMessage(), e);
        } catch (final IOException e) {
            throw new IndexException(e.getLocalizedMessage(), e);
        } finally {
            if (writer != null) {
                try {
                    writer.close();
                } catch (CorruptIndexException e) {
                    throw new IndexException(e.getLocalizedMessage(), e);
                } catch (IOException e) {
                    throw new IndexException(e.getLocalizedMessage(), e);
                }
            }
        }
    }

    /**
     * @throws CorruptIndexException
     * @throws LockObtainFailedException
     * @throws IOException
     */
    private void initDirectory() throws IndexException {
        try {
            IndexWriter.MaxFieldLength fieldLength = new IndexWriter.MaxFieldLength(
                    IndexWriter.DEFAULT_MAX_FIELD_LENGTH);
            IndexWriter iw = new IndexWriter(indexDirectiry, new SimpleAnalyzer(), true, fieldLength);
            iw.close();
        } catch (IOException e) {
            throw new IndexException(e.getLocalizedMessage(), e);
        }
    }
}