001    /**
002     * Copyright (c) 2000-present 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                    try (ObjectInputStream objectInputStream = new ObjectInputStream(
052                                    inputStream)) {
053    
054                            IndexCommitMetaInfo indexCommitMetaInfo = null;
055    
056                            try {
057                                    indexCommitMetaInfo =
058                                            (IndexCommitMetaInfo)objectInputStream.readObject();
059                            }
060                            catch (ClassNotFoundException cnfe) {
061                                    throw new IOException(cnfe);
062                            }
063    
064                            if (_log.isDebugEnabled()) {
065                                    _log.debug("Deserializing " + indexCommitMetaInfo);
066                            }
067    
068                            if (indexCommitMetaInfo.isEmpty()) {
069                                    return;
070                            }
071    
072                            List<Segment> segments = indexCommitMetaInfo.getSegments();
073    
074                            for (Segment segment : segments) {
075                                    if (_log.isDebugEnabled()) {
076                                            _log.debug("Deserializing segment " + segment);
077                                    }
078    
079                                    _deserializeSegment(
080                                            objectInputStream, segment.getFileSize(),
081                                            directory.createOutput(segment.getFileName()));
082                            }
083    
084                            _writeSegmentsGen(directory, indexCommitMetaInfo.getGeneration());
085                    }
086            }
087    
088            public static void serializeIndex(
089                            IndexCommit indexCommit, OutputStream outputStream)
090                    throws IOException {
091    
092                    if (PropsValues.INDEX_DUMP_COMPRESSION_ENABLED) {
093                            outputStream = new GZIPOutputStream(outputStream);
094                    }
095    
096                    ObjectOutputStream objectOputStream = new ObjectOutputStream(
097                            outputStream);
098    
099                    IndexCommitMetaInfo indexCommitMetaInfo = new IndexCommitMetaInfo(
100                            indexCommit);
101    
102                    if (_log.isDebugEnabled()) {
103                            _log.debug("Serializing " + indexCommitMetaInfo);
104                    }
105    
106                    objectOputStream.writeObject(indexCommitMetaInfo);
107    
108                    List<Segment> segments = indexCommitMetaInfo.getSegments();
109    
110                    Directory directory = indexCommit.getDirectory();
111    
112                    for (Segment segment : segments) {
113                            if (_log.isDebugEnabled()) {
114                                    _log.debug("Serializing segment " + segment);
115                            }
116    
117                            _serializeSegment(
118                                    directory.openInput(segment.getFileName()),
119                                    segment.getFileSize(), objectOputStream);
120                    }
121    
122                    objectOputStream.flush();
123    
124                    if (PropsValues.INDEX_DUMP_COMPRESSION_ENABLED) {
125                            GZIPOutputStream gZipOutputStream = (GZIPOutputStream)outputStream;
126    
127                            gZipOutputStream.finish();
128                    }
129            }
130    
131            private static void _deserializeSegment(
132                            InputStream inputStream, long length, IndexOutput indexOutput)
133                    throws IOException {
134    
135                    try {
136                            indexOutput.setLength(length);
137    
138                            byte[] buffer = new byte[_BUFFER_SIZE];
139    
140                            long received = 0;
141    
142                            while (received < length) {
143                                    int bufferSize = _BUFFER_SIZE;
144    
145                                    if ((received + _BUFFER_SIZE) > length) {
146                                            bufferSize = (int)(length - received);
147                                    }
148    
149                                    int actualSize = inputStream.read(buffer, 0, bufferSize);
150    
151                                    indexOutput.writeBytes(buffer, actualSize);
152    
153                                    received += actualSize;
154                            }
155                    }
156                    finally {
157                            indexOutput.close();
158                    }
159            }
160    
161            private static void _serializeSegment(
162                            IndexInput indexInput, long length, OutputStream outputStream)
163                    throws IOException {
164    
165                    byte[] buffer = new byte[_BUFFER_SIZE];
166    
167                    int count = (int)(length / _BUFFER_SIZE);
168                    int tail = (int)(length - count * _BUFFER_SIZE);
169    
170                    try {
171                            for (int i = 0; i < count; i++) {
172                                    indexInput.readBytes(buffer, 0, _BUFFER_SIZE);
173                                    outputStream.write(buffer);
174                            }
175    
176                            indexInput.readBytes(buffer, 0, tail);
177                            outputStream.write(buffer, 0, tail);
178                    }
179                    finally {
180                            indexInput.close();
181                    }
182            }
183    
184            private static void _writeSegmentsGen(Directory directory, long generation)
185                    throws IOException {
186    
187                    if (_log.isDebugEnabled()) {
188                            _log.debug(
189                                    "Writing " + _SEGMENTS_GEN_FILE_NAME + " with generation " +
190                                            generation);
191                    }
192    
193                    try (IndexOutput indexOutput = directory.createOutput(
194                                    _SEGMENTS_GEN_FILE_NAME)) {
195    
196                            indexOutput.writeInt(SegmentInfos.FORMAT_LOCKLESS);
197                            indexOutput.writeLong(generation);
198                            indexOutput.writeLong(generation);
199                    }
200            }
201    
202            private static final int _BUFFER_SIZE = 8192;
203    
204            private static final String _SEGMENTS_GEN_FILE_NAME = "segments.gen";
205    
206            private static Log _log = LogFactoryUtil.getLog(
207                    IndexCommitSerializationUtil.class);
208    
209    }