001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.search.lucene.dump;
016    
017    import com.liferay.portal.kernel.log.Log;
018    import com.liferay.portal.kernel.log.LogFactoryUtil;
019    import com.liferay.portal.search.lucene.dump.IndexCommitMetaInfo.Segment;
020    import com.liferay.portal.util.PropsValues;
021    
022    import java.io.IOException;
023    import java.io.InputStream;
024    import java.io.ObjectInputStream;
025    import java.io.ObjectOutputStream;
026    import java.io.OutputStream;
027    
028    import java.util.List;
029    import java.util.zip.GZIPInputStream;
030    import java.util.zip.GZIPOutputStream;
031    
032    import org.apache.lucene.index.IndexCommit;
033    import org.apache.lucene.index.SegmentInfos;
034    import org.apache.lucene.store.Directory;
035    import org.apache.lucene.store.IndexInput;
036    import org.apache.lucene.store.IndexOutput;
037    
038    /**
039     * @author Shuyang Zhou
040     */
041    public class IndexCommitSerializationUtil {
042    
043            public static void deserializeIndex(
044                            InputStream inputStream, Directory directory)
045                    throws IOException {
046    
047                    if (PropsValues.INDEX_DUMP_COMPRESSION_ENABLED) {
048                            inputStream = new GZIPInputStream(inputStream);
049                    }
050    
051                    ObjectInputStream objectInputStream = null;
052    
053                    try {
054                            objectInputStream = new ObjectInputStream(inputStream);
055    
056                            IndexCommitMetaInfo indexCommitMetaInfo = null;
057    
058                            try {
059                                    indexCommitMetaInfo =
060                                            (IndexCommitMetaInfo)objectInputStream.readObject();
061                            }
062                            catch (ClassNotFoundException cnfe) {
063                                    throw new IOException(cnfe.getMessage());
064                            }
065    
066                            if (_log.isDebugEnabled()) {
067                                    _log.debug("Deserializing " + indexCommitMetaInfo);
068                            }
069    
070                            if (indexCommitMetaInfo.isEmpty()) {
071                                    return;
072                            }
073    
074                            List<Segment> segments = indexCommitMetaInfo.getSegments();
075    
076                            for (Segment segment : segments) {
077                                    if (_log.isDebugEnabled()) {
078                                            _log.debug("Deserializing segment " + segment);
079                                    }
080    
081                                    _deserializeSegment(
082                                            objectInputStream, segment.getFileSize(),
083                                            directory.createOutput(segment.getFileName()));
084                            }
085    
086                            _writeSegmentsGen(directory, indexCommitMetaInfo.getGeneration());
087                    }
088                    finally {
089                            if (objectInputStream != null) {
090                                    objectInputStream.close();
091                            }
092                    }
093            }
094    
095            public static void serializeIndex(
096                            IndexCommit indexCommit, OutputStream outputStream)
097                    throws IOException {
098    
099                    if (PropsValues.INDEX_DUMP_COMPRESSION_ENABLED) {
100                            outputStream = new GZIPOutputStream(outputStream);
101                    }
102    
103                    ObjectOutputStream objectOputStream = new ObjectOutputStream(
104                            outputStream);
105    
106                    IndexCommitMetaInfo indexCommitMetaInfo = new IndexCommitMetaInfo(
107                            indexCommit);
108    
109                    if (_log.isDebugEnabled()) {
110                            _log.debug("Serializing " + indexCommitMetaInfo);
111                    }
112    
113                    objectOputStream.writeObject(indexCommitMetaInfo);
114    
115                    List<Segment> segments = indexCommitMetaInfo.getSegments();
116    
117                    Directory directory = indexCommit.getDirectory();
118    
119                    for (Segment segment : segments) {
120                            if (_log.isDebugEnabled()) {
121                                    _log.debug("Serializing segment " + segment);
122                            }
123    
124                            _serializeSegment(
125                                    directory.openInput(segment.getFileName()),
126                                    segment.getFileSize(), objectOputStream);
127                    }
128    
129                    objectOputStream.flush();
130    
131                    if (PropsValues.INDEX_DUMP_COMPRESSION_ENABLED) {
132                            GZIPOutputStream gZipOutputStream = (GZIPOutputStream)outputStream;
133    
134                            gZipOutputStream.finish();
135                    }
136            }
137    
138            private static void _deserializeSegment(
139                            InputStream inputStream, long length, IndexOutput indexOutput)
140                    throws IOException {
141    
142                    try {
143                            indexOutput.setLength(length);
144    
145                            byte[] buffer = new byte[_BUFFER_SIZE];
146    
147                            long received = 0;
148    
149                            while (received < length) {
150                                    int bufferSize = _BUFFER_SIZE;
151    
152                                    if ((received + _BUFFER_SIZE) > length) {
153                                            bufferSize = (int)(length - received);
154                                    }
155    
156                                    int actualSize = inputStream.read(buffer, 0, bufferSize);
157    
158                                    indexOutput.writeBytes(buffer, actualSize);
159    
160                                    received += actualSize;
161                            }
162                    }
163                    finally {
164                            indexOutput.close();
165                    }
166            }
167    
168            private static void _serializeSegment(
169                            IndexInput indexInput, long length, OutputStream outputStream)
170                    throws IOException {
171    
172                    byte[] buffer = new byte[_BUFFER_SIZE];
173    
174                    int count = (int)(length / _BUFFER_SIZE);
175                    int tail = (int)(length - count * _BUFFER_SIZE);
176    
177                    try {
178                            for (int i = 0; i < count; i++) {
179                                    indexInput.readBytes(buffer, 0, _BUFFER_SIZE);
180                                    outputStream.write(buffer);
181                            }
182    
183                            indexInput.readBytes(buffer, 0, tail);
184                            outputStream.write(buffer, 0, tail);
185                    }
186                    finally {
187                            indexInput.close();
188                    }
189            }
190    
191            private static void _writeSegmentsGen(Directory directory, long generation)
192                    throws IOException {
193    
194                    if (_log.isDebugEnabled()) {
195                            _log.debug(
196                                    "Writing " + _SEGMENTS_GEN_FILE_NAME + " with generation " +
197                                            generation);
198                    }
199    
200                    IndexOutput indexOutput = directory.createOutput(
201                            _SEGMENTS_GEN_FILE_NAME);
202    
203                    try {
204                            indexOutput.writeInt(SegmentInfos.FORMAT_LOCKLESS);
205                            indexOutput.writeLong(generation);
206                            indexOutput.writeLong(generation);
207                    }
208                    finally {
209                            indexOutput.close();
210                    }
211            }
212    
213            private static final int _BUFFER_SIZE = 8192;
214    
215            private static final String _SEGMENTS_GEN_FILE_NAME = "segments.gen";
216    
217            private static Log _log = LogFactoryUtil.getLog(
218                    IndexCommitSerializationUtil.class);
219    
220    }