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
33 import edu.emory.mathcs.backport.java.util.concurrent.Semaphore;
34
35 import java.io.IOException;
36
37 import java.util.Iterator;
38 import java.util.List;
39 import java.util.Map;
40
41 import org.apache.commons.logging.Log;
42 import org.apache.commons.logging.LogFactory;
43 import org.apache.lucene.index.IndexReader;
44 import org.apache.lucene.index.IndexWriter;
45 import org.apache.lucene.index.Term;
46
47
67 public class IndexWriterFactory {
68
69 public IndexWriterFactory() {
70
71
73 try {
74 List companies = CompanyLocalServiceUtil.getCompanies();
75
76 for (int i = 0; i < companies.size(); i++) {
77 Company company = (Company)companies.get(i);
78
79 _lockLookup.put(
80 new Long(company.getCompanyId()), new Semaphore(1));
81 }
82
83 _lockLookup.put(new Long(CompanyImpl.SYSTEM), new Semaphore(1));
84 }
85 catch (SystemException se) {
86 _log.error(se);
87 }
88 }
89
90 public void acquireLock(long companyId, boolean needExclusive)
91 throws InterruptedException {
92
93 Semaphore lock = (Semaphore)_lockLookup.get(new Long(companyId));
94
95 if (lock != null) {
96
97
101 if (needExclusive) {
102 synchronized (_lockLookup) {
103 _needExclusiveLock++;
104 }
105 }
106
107 try {
108 lock.acquire();
109 }
110 finally {
111 if (needExclusive) {
112 synchronized (_lockLookup) {
113 _needExclusiveLock--;
114 }
115 }
116 }
117 }
118 else {
119 if (_log.isWarnEnabled()) {
120 _log.warn("IndexWriterFactory lock not found for " + companyId);
121 }
122 }
123 }
124
125 public void deleteDocuments(long companyId, Term term)
126 throws InterruptedException, IOException {
127
128 try {
129 acquireLock(companyId, true);
130
131 IndexReader reader = null;
132
133 try {
134 reader = IndexReader.open(LuceneUtil.getLuceneDir(companyId));
135
136 reader.deleteDocuments(term);
137 }
138 finally {
139 if (reader != null) {
140 reader.close();
141 }
142 }
143 }
144 finally {
145 releaseLock(companyId);
146 }
147 }
148
149 public IndexWriter getWriter(long companyId, boolean create)
150 throws IOException {
151
152 Long companyIdObj = new Long(companyId);
153
154 boolean hasError = false;
155 boolean newWriter = false;
156
157 try {
158
159
162 if (_needExclusiveLock > 0) {
163 acquireLock(companyId, false);
164 releaseLock(companyId);
165 }
166
167 synchronized(this) {
168 IndexWriterData writerData =
169 (IndexWriterData)_writerLookup.get(companyIdObj);
170
171 if (writerData == null) {
172 newWriter = true;
173
174 acquireLock(companyId, false);
175
176 IndexWriter writer = new IndexWriter(
177 LuceneUtil.getLuceneDir(companyId),
178 LuceneUtil.getAnalyzer(), create);
179
180 writer.setMergeFactor(_MERGE_FACTOR);
181
182 writerData = new IndexWriterData(companyId, writer, 0);
183
184 _writerLookup.put(companyIdObj, writerData);
185 }
186
187 writerData.setCount(writerData.getCount() + 1);
188
189 return writerData.getWriter();
190 }
191 }
192 catch (Exception e) {
193 hasError = true;
194
195 _log.error("Unable to create a new writer", e);
196
197 throw new IOException("Unable to create a new writer");
198 }
199 finally {
200 if (hasError && newWriter) {
201 try {
202 releaseLock(companyId);
203 }
204 catch (Exception e) {
205 }
206 }
207 }
208 }
209
210 public void releaseLock(long companyId) {
211 Semaphore lock = (Semaphore)_lockLookup.get(new Long(companyId));
212
213 if (lock != null) {
214 lock.release();
215 }
216 }
217
218 public void write(long companyId) throws IOException {
219 IndexWriterData writerData =
220 (IndexWriterData)_writerLookup.get(new Long(companyId));
221
222 if (writerData != null) {
223 decrement(writerData);
224 }
225 else {
226 if (_log.isWarnEnabled()) {
227 _log.warn("IndexWriterData not found for " + companyId);
228 }
229 }
230 }
231
232 public void write(IndexWriter writer) throws IOException {
233 boolean writerFound = false;
234
235 synchronized(this) {
236 if (!_writerLookup.isEmpty()) {
237 Iterator itr = _writerLookup.values().iterator();
238
239 while (itr.hasNext()) {
240 IndexWriterData writerData = (IndexWriterData)itr.next();
241
242 if (writerData.getWriter() == writer) {
243 writerFound = true;
244
245 decrement(writerData);
246
247 break;
248 }
249 }
250 }
251 }
252
253 if (!writerFound) {
254 try {
255 _optimizeCount++;
256
257 if ((_OPTIMIZE_INTERVAL == 0) ||
258 (_optimizeCount >= _OPTIMIZE_INTERVAL)) {
259
260 writer.optimize();
261
262 _optimizeCount = 0;
263 }
264 }
265 finally {
266 writer.close();
267 }
268 }
269 }
270
271 protected void decrement(IndexWriterData writerData) throws IOException {
272 if (writerData.getCount() > 0) {
273 writerData.setCount(writerData.getCount() - 1);
274
275 if (writerData.getCount() == 0) {
276 _writerLookup.remove(new Long(writerData.getCompanyId()));
277
278 try {
279 IndexWriter writer = writerData.getWriter();
280
281 try {
282 _optimizeCount++;
283
284 if ((_OPTIMIZE_INTERVAL == 0) ||
285 (_optimizeCount >= _OPTIMIZE_INTERVAL)) {
286
287 writer.optimize();
288
289 _optimizeCount = 0;
290 }
291 }
292 finally {
293 writer.close();
294 }
295 }
296 catch (Exception e) {
297 _log.error(e, e);
298 }
299 finally {
300 releaseLock(writerData.getCompanyId());
301 }
302 }
303 }
304 }
305
306 private static final int _MERGE_FACTOR = GetterUtil.getInteger(
307 PropsUtil.get(PropsUtil.LUCENE_MERGE_FACTOR));
308
309 private static final int _OPTIMIZE_INTERVAL = GetterUtil.getInteger(
310 PropsUtil.get(PropsUtil.LUCENE_OPTIMIZE_INTERVAL));
311
312 private static Log _log = LogFactory.getLog(IndexWriterFactory.class);
313
314 private Map _lockLookup = CollectionFactory.getHashMap();
315 private Map _writerLookup = CollectionFactory.getHashMap();
316 private int _needExclusiveLock = 0;
317 private int _optimizeCount = 0;
318
319 }