1
22
23 package com.liferay.portal.search.lucene;
24
25 import com.liferay.portal.SystemException;
26 import com.liferay.portal.kernel.log.Log;
27 import com.liferay.portal.kernel.log.LogFactoryUtil;
28 import com.liferay.portal.kernel.util.GetterUtil;
29 import com.liferay.portal.model.Company;
30 import com.liferay.portal.model.CompanyConstants;
31 import com.liferay.portal.service.CompanyLocalServiceUtil;
32 import com.liferay.portal.util.PropsKeys;
33 import com.liferay.portal.util.PropsUtil;
34 import com.liferay.portal.util.PropsValues;
35 import com.liferay.util.SystemProperties;
36
37 import java.io.File;
38 import java.io.IOException;
39
40 import java.util.HashMap;
41 import java.util.List;
42 import java.util.Map;
43 import java.util.concurrent.Semaphore;
44
45 import org.apache.lucene.analysis.SimpleAnalyzer;
46 import org.apache.lucene.index.IndexReader;
47 import org.apache.lucene.index.IndexWriter;
48 import org.apache.lucene.index.Term;
49 import org.apache.lucene.store.Directory;
50 import org.apache.lucene.store.FSDirectory;
51
52
72 public class IndexWriterFactory {
73
74 public IndexWriterFactory() {
75 if (PropsValues.INDEX_READ_ONLY) {
76 return;
77 }
78
79
81 try {
82 List<Company> companies = CompanyLocalServiceUtil.getCompanies();
83
84 for (Company company : companies) {
85 _lockLookup.put(company.getCompanyId(), new Semaphore(1));
86 }
87
88 _lockLookup.put(CompanyConstants.SYSTEM, new Semaphore(1));
89 }
90 catch (SystemException se) {
91 _log.error(se);
92 }
93 }
94
95 public void acquireLock(long companyId, boolean needExclusive)
96 throws InterruptedException {
97
98 if (PropsValues.INDEX_READ_ONLY) {
99 return;
100 }
101
102 Semaphore lock = _lockLookup.get(companyId);
103
104 if (lock != null) {
105
106
110 if (needExclusive) {
111 synchronized (_lockLookup) {
112 _needExclusiveLock++;
113 }
114 }
115
116 try {
117 lock.acquire();
118 }
119 finally {
120 if (needExclusive) {
121 synchronized (_lockLookup) {
122 _needExclusiveLock--;
123 }
124 }
125 }
126 }
127 else {
128 if (_log.isWarnEnabled()) {
129 _log.warn("IndexWriterFactory lock not found for " + companyId);
130 }
131 }
132 }
133
134 public void deleteDocuments(long companyId, Term term)
135 throws InterruptedException, IOException {
136
137 if (PropsValues.INDEX_READ_ONLY) {
138 return;
139 }
140
141 try {
142 acquireLock(companyId, true);
143
144 IndexReader reader = null;
145
146 try {
147 reader = IndexReader.open(LuceneUtil.getLuceneDir(companyId));
148
149 reader.deleteDocuments(term);
150 }
151 finally {
152 if (reader != null) {
153 reader.close();
154 }
155 }
156 }
157 finally {
158 releaseLock(companyId);
159 }
160 }
161
162 public IndexWriter getWriter(long companyId, boolean create)
163 throws IOException {
164
165 if (PropsValues.INDEX_READ_ONLY) {
166 return getReadOnlyIndexWriter();
167 }
168
169 boolean hasError = false;
170 boolean newWriter = false;
171
172 try {
173
174
177 if (_needExclusiveLock > 0) {
178 acquireLock(companyId, false);
179 releaseLock(companyId);
180 }
181
182 synchronized (this) {
183 IndexWriterData writerData = _writerLookup.get(companyId);
184
185 if (writerData == null) {
186 newWriter = true;
187
188 acquireLock(companyId, false);
189
190 IndexWriter writer = new IndexWriter(
191 LuceneUtil.getLuceneDir(companyId),
192 LuceneUtil.getAnalyzer(), create);
193
194 writer.setMergeFactor(_MERGE_FACTOR);
195
196 writerData = new IndexWriterData(companyId, writer, 0);
197
198 _writerLookup.put(companyId, writerData);
199 }
200
201 writerData.setCount(writerData.getCount() + 1);
202
203 return writerData.getWriter();
204 }
205 }
206 catch (Exception e) {
207 hasError = true;
208
209 _log.error("Unable to create a new writer", e);
210
211 throw new IOException("Unable to create a new writer");
212 }
213 finally {
214 if (hasError && newWriter) {
215 try {
216 releaseLock(companyId);
217 }
218 catch (Exception e) {
219 }
220 }
221 }
222 }
223
224 public void releaseLock(long companyId) {
225 if (PropsValues.INDEX_READ_ONLY) {
226 return;
227 }
228
229 Semaphore lock = _lockLookup.get(companyId);
230
231 if (lock != null) {
232 lock.release();
233 }
234 }
235
236 public void write(long companyId) {
237 if (PropsValues.INDEX_READ_ONLY) {
238 return;
239 }
240
241 IndexWriterData writerData = _writerLookup.get(companyId);
242
243 if (writerData != null) {
244 decrement(writerData);
245 }
246 else {
247 if (_log.isWarnEnabled()) {
248 _log.warn("IndexWriterData not found for " + companyId);
249 }
250 }
251 }
252
253 public void write(IndexWriter writer) throws IOException {
254 if (PropsValues.INDEX_READ_ONLY) {
255 return;
256 }
257
258 boolean writerFound = false;
259
260 synchronized (this) {
261 if (!_writerLookup.isEmpty()) {
262 for (IndexWriterData writerData : _writerLookup.values()) {
263 if (writerData.getWriter() == writer) {
264 writerFound = true;
265
266 decrement(writerData);
267
268 break;
269 }
270 }
271 }
272 }
273
274 if (!writerFound) {
275 try {
276 _optimizeCount++;
277
278 if ((_OPTIMIZE_INTERVAL == 0) ||
279 (_optimizeCount >= _OPTIMIZE_INTERVAL)) {
280
281 writer.optimize();
282
283 _optimizeCount = 0;
284 }
285 }
286 finally {
287 writer.close();
288 }
289 }
290 }
291
292 protected void decrement(IndexWriterData writerData) {
293 if (writerData.getCount() > 0) {
294 writerData.setCount(writerData.getCount() - 1);
295
296 if (writerData.getCount() == 0) {
297 _writerLookup.remove(writerData.getCompanyId());
298
299 try {
300 IndexWriter writer = writerData.getWriter();
301
302 try {
303 _optimizeCount++;
304
305 if ((_OPTIMIZE_INTERVAL == 0) ||
306 (_optimizeCount >= _OPTIMIZE_INTERVAL)) {
307
308 writer.optimize();
309
310 _optimizeCount = 0;
311 }
312 }
313 finally {
314 writer.close();
315 }
316 }
317 catch (Exception e) {
318 _log.error(e, e);
319 }
320 finally {
321 releaseLock(writerData.getCompanyId());
322 }
323 }
324 }
325 }
326
327 protected IndexWriter getReadOnlyIndexWriter() {
328 if (_readOnlyIndexWriter == null) {
329 try {
330 if (_log.isInfoEnabled()) {
331 _log.info("Disabling writing to index for this process");
332 }
333
334 _readOnlyIndexWriter = new ReadOnlyIndexWriter(
335 getReadOnlyLuceneDir(), new SimpleAnalyzer(), true);
336 }
337 catch (IOException ioe) {
338 throw new RuntimeException(ioe);
339 }
340 }
341
342 return _readOnlyIndexWriter;
343 }
344
345 protected Directory getReadOnlyLuceneDir() throws IOException {
346 if (_readOnlyLuceneDir == null) {
347 String tmpDir = SystemProperties.get(SystemProperties.TMP_DIR);
348
349 File dir = new File(tmpDir + "/liferay/lucene/empty");
350
351 dir.mkdir();
352
353 _readOnlyLuceneDir = LuceneUtil.getDirectory(dir.getPath(), false);
354 }
355
356 return _readOnlyLuceneDir;
357 }
358
359 private static final int _MERGE_FACTOR = GetterUtil.getInteger(
360 PropsUtil.get(PropsKeys.LUCENE_MERGE_FACTOR));
361
362 private static final int _OPTIMIZE_INTERVAL = GetterUtil.getInteger(
363 PropsUtil.get(PropsKeys.LUCENE_OPTIMIZE_INTERVAL));
364
365 private static Log _log = LogFactoryUtil.getLog(IndexWriterFactory.class);
366
367 private FSDirectory _readOnlyLuceneDir = null;
368 private IndexWriter _readOnlyIndexWriter = null;
369 private Map<Long, Semaphore> _lockLookup = new HashMap<Long, Semaphore>();
370 private Map<Long, IndexWriterData> _writerLookup =
371 new HashMap<Long, IndexWriterData>();
372 private int _needExclusiveLock = 0;
373 private int _optimizeCount = 0;
374
375 }