001    /**
002     * Copyright (c) 2000-2011 Liferay, Inc. All rights reserved.
003     *
004     * The contents of this file are subject to the terms of the Liferay Enterprise
005     * Subscription License ("License"). You may not use this file except in
006     * compliance with the License. You can obtain a copy of the License by
007     * contacting Liferay, Inc. See the License for the specific language governing
008     * permissions and limitations under the License, including but not limited to
009     * distribution rights of the Software.
010     *
011     *
012     *
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(
087                                    directory, indexCommitMetaInfo.getGeneration());
088                    }
089                    finally {
090                            if (objectInputStream != null) {
091                                    objectInputStream.close();
092                            }
093                    }
094            }
095    
096            public static void serializeIndex(
097                            IndexCommit indexCommit, OutputStream outputStream)
098                    throws IOException {
099    
100                    if (PropsValues.INDEX_DUMP_COMPRESSION_ENABLED) {
101                            outputStream = new GZIPOutputStream(outputStream);
102                    }
103    
104                    ObjectOutputStream objectOputStream = new ObjectOutputStream(
105                            outputStream);
106    
107                    IndexCommitMetaInfo indexCommitMetaInfo = new IndexCommitMetaInfo(
108                            indexCommit);
109    
110                    if (_log.isDebugEnabled()) {
111                            _log.debug("Serializing " + indexCommitMetaInfo);
112                    }
113    
114                    objectOputStream.writeObject(indexCommitMetaInfo);
115    
116                    List<Segment> segments = indexCommitMetaInfo.getSegments();
117    
118                    Directory directory = indexCommit.getDirectory();
119    
120                    for (Segment segment : segments) {
121                            if (_log.isDebugEnabled()) {
122                                    _log.debug("Serializing segment " + segment);
123                            }
124    
125                            serializeSegment(
126                                    directory.openInput(segment.getFileName()),
127                                    segment.getFileSize(), objectOputStream);
128                    }
129    
130                    objectOputStream.flush();
131    
132                    if (PropsValues.INDEX_DUMP_COMPRESSION_ENABLED) {
133                            GZIPOutputStream gZipOutputStream = (GZIPOutputStream)outputStream;
134    
135                            gZipOutputStream.finish();
136                    }
137            }
138    
139            private static void deserializeSegment(
140                            InputStream inputStream, long length, IndexOutput indexOutput)
141                    throws IOException {
142    
143                    try {
144                            indexOutput.setLength(length);
145    
146                            byte[] buffer = new byte[_BUFFER_SIZE];
147    
148                            long received = 0;
149    
150                            while (received < length) {
151                                    int bufferSize = _BUFFER_SIZE;
152    
153                                    if ((received + _BUFFER_SIZE) > length) {
154                                            bufferSize = (int)(length - received);
155                                    }
156    
157                                    int actualSize = inputStream.read(buffer, 0, bufferSize);
158    
159                                    indexOutput.writeBytes(buffer, actualSize);
160    
161                                    received += actualSize;
162                            }
163                    }
164                    finally {
165                            indexOutput.close();
166                    }
167            }
168    
169            private static void serializeSegment(
170                            IndexInput indexInput, long length, OutputStream outputStream)
171                    throws IOException {
172    
173                    byte[] buffer = new byte[_BUFFER_SIZE];
174    
175                    int count = (int)(length / _BUFFER_SIZE);
176                    int tail = (int)(length - count * _BUFFER_SIZE);
177    
178                    try {
179                            for (int i = 0; i < count; i++) {
180                                    indexInput.readBytes(buffer, 0, _BUFFER_SIZE);
181                                    outputStream.write(buffer);
182                            }
183    
184                            indexInput.readBytes(buffer, 0, tail);
185                            outputStream.write(buffer, 0, tail);
186                    }
187                    finally {
188                            indexInput.close();
189                    }
190            }
191    
192            private static void writeSegmentsGen(
193                            Directory directory, long generation)
194                    throws IOException {
195    
196                    if (_log.isDebugEnabled()) {
197                            _log.debug(
198                                    "Writing " + _SEGMENTS_GEN_FILE_NAME + " with generation " +
199                                            generation);
200                    }
201    
202                    IndexOutput indexOutput = directory.createOutput(
203                            _SEGMENTS_GEN_FILE_NAME);
204    
205                    try {
206                            indexOutput.writeInt(SegmentInfos.FORMAT_LOCKLESS);
207                            indexOutput.writeLong(generation);
208                            indexOutput.writeLong(generation);
209                    }
210                    finally {
211                            indexOutput.close();
212                    }
213            }
214    
215            private static final int _BUFFER_SIZE = 8192;
216    
217            private static final String _SEGMENTS_GEN_FILE_NAME = "segments.gen";
218    
219            private static Log _log = LogFactoryUtil.getLog(
220                    IndexCommitSerializationUtil.class);
221    
222    }