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