Mercurial Hosting > luan
comparison src/luan/modules/lucene/LuceneIndex.java @ 1397:0dc9837c16be
fix lucene issues
author | Franklin Schmidt <fschmidt@gmail.com> |
---|---|
date | Wed, 11 Sep 2019 01:31:21 -0600 |
parents | 9dfff82dfc59 |
children | 67c0e47b5be3 |
comparison
equal
deleted
inserted
replaced
1396:a5f61890ad84 | 1397:0dc9837c16be |
---|---|
3 import java.io.Closeable; | 3 import java.io.Closeable; |
4 import java.io.File; | 4 import java.io.File; |
5 import java.io.FileOutputStream; | 5 import java.io.FileOutputStream; |
6 import java.io.FileInputStream; | 6 import java.io.FileInputStream; |
7 import java.io.IOException; | 7 import java.io.IOException; |
8 import java.lang.ref.Reference; | |
9 import java.lang.ref.WeakReference; | |
8 import java.sql.SQLException; | 10 import java.sql.SQLException; |
9 import java.util.Arrays; | 11 import java.util.Arrays; |
10 import java.util.Iterator; | 12 import java.util.Iterator; |
11 import java.util.Map; | 13 import java.util.Map; |
12 import java.util.HashMap; | 14 import java.util.HashMap; |
81 import luan.modules.parsers.LuanToString; | 83 import luan.modules.parsers.LuanToString; |
82 import luan.lib.logging.Logger; | 84 import luan.lib.logging.Logger; |
83 import luan.lib.logging.LoggerFactory; | 85 import luan.lib.logging.LoggerFactory; |
84 | 86 |
85 | 87 |
86 public final class LuceneIndex { | 88 public final class LuceneIndex implements Closeable { |
87 private static final Logger sysLogger = LoggerFactory.getLogger(LuceneIndex.class); | 89 private static final Logger sysLogger = LoggerFactory.getLogger(LuceneIndex.class); |
88 | 90 |
89 private static final class Closer implements Closeable { | 91 private static Map<String,Reference<LuceneIndex>> indexes = new HashMap<String,Reference<LuceneIndex>>(); |
90 final LuceneIndex li; | 92 |
91 boolean isClosed = false; | 93 public static LuceneIndex getLuceneIndex(Luan luan,File indexDir,LuanTable options) |
92 private final Exception created = new Exception("created"); | |
93 | |
94 Closer(Luan luan,LuceneIndex li) { | |
95 this.li = li; | |
96 luan.onClose(this); | |
97 } | |
98 | |
99 public void close() throws IOException { | |
100 if( !isClosed ) { | |
101 try { | |
102 li.close(); | |
103 } catch(SQLException e) { | |
104 throw new RuntimeException(e); | |
105 } | |
106 isClosed = true; | |
107 } | |
108 } | |
109 | |
110 protected void finalize() throws Throwable { | |
111 if( !isClosed ) { | |
112 sysLogger.error("not closed",created); | |
113 close(); | |
114 } | |
115 super.finalize(); | |
116 } | |
117 } | |
118 | |
119 private static Map<String,LuceneIndex> indexes = new HashMap<String,LuceneIndex>(); | |
120 | |
121 public static Object[] getLuceneIndex(Luan luan,File indexDir,FieldParser defaultFieldParser,String[] defaultFields,LuanFunction completer,LuanTable postgresSpec) | |
122 throws LuanException, IOException, ClassNotFoundException, SQLException | 94 throws LuanException, IOException, ClassNotFoundException, SQLException |
123 { | 95 { |
124 String key = indexDir.getCanonicalPath(); | 96 String key = indexDir.getCanonicalPath(); |
125 synchronized(indexes) { | 97 synchronized(indexes) { |
126 LuceneIndex li = indexes.get(key); | 98 Reference<LuceneIndex> ref = indexes.get(key); |
127 if( li == null ) { | 99 if( ref != null ) { |
128 li = new LuceneIndex(luan,indexDir,defaultFieldParser,defaultFields,key,completer,postgresSpec); | 100 LuceneIndex li = ref.get(); |
129 li.openCount = 1; | 101 if( li != null ) |
130 indexes.put(key,li); | 102 li.closeWriter(); |
131 } else { | 103 } |
132 if( defaultFieldParser != li.defaultFieldParser ) | 104 LuceneIndex li = new LuceneIndex(luan,indexDir,options); |
133 throw new LuanException("default_type doesn't match previous use"); | 105 indexes.put(key, new WeakReference<LuceneIndex>(li)); |
134 if( !Arrays.equals(defaultFields,li.defaultFields) ) | 106 return li; |
135 throw new LuanException("default_fields don't match previous use"); | |
136 li.openCount++; | |
137 } | |
138 return new Object[]{li,new Closer(luan,li)}; | |
139 } | 107 } |
140 } | 108 } |
141 | 109 |
142 private static final Version version = Version.LUCENE_4_9; | 110 private static final Version version = Version.LUCENE_4_9; |
143 private static final String FLD_NEXT_ID = "nextId"; | 111 private static final String FLD_NEXT_ID = "nextId"; |
160 private int writeCount; | 128 private int writeCount; |
161 private AtomicInteger writeCounter = new AtomicInteger(); | 129 private AtomicInteger writeCounter = new AtomicInteger(); |
162 | 130 |
163 private Set<String> indexOnly = new HashSet<String>(); | 131 private Set<String> indexOnly = new HashSet<String>(); |
164 | 132 |
165 private int openCount; | 133 private boolean isClosed = false; |
166 private final String key; | 134 private final Exception created = new Exception("created"); |
167 private final FieldParser defaultFieldParser; | 135 private final FieldParser defaultFieldParser; |
168 private final String[] defaultFields; | 136 private final String[] defaultFields; |
169 | 137 |
170 private final PostgresBackup postgresBackup; | 138 private final PostgresBackup postgresBackup; |
171 | 139 private boolean wasCreated; |
172 private LuceneIndex(Luan luan,File indexDir,FieldParser defaultFieldParser,String[] defaultFields,String key,LuanFunction completer,LuanTable postgresSpec) | 140 |
141 private LuceneIndex(Luan luan,File indexDir,LuanTable options) | |
173 throws LuanException, IOException, ClassNotFoundException, SQLException | 142 throws LuanException, IOException, ClassNotFoundException, SQLException |
174 { | 143 { |
144 Map map = options.asMap(); | |
145 FieldParser defaultFieldParser = (FieldParser)map.remove("default_type"); | |
146 LuanTable defaultFieldsTbl = Utils.removeTable(map,"default_fields"); | |
147 String[] defaultFields = defaultFieldsTbl==null ? null : (String[])defaultFieldsTbl.asList().toArray(new String[0]); | |
148 LuanFunction completer = Utils.removeFunction(map,"completer"); | |
149 LuanTable postgresSpec = Utils.removeTable(map,"postgres_spec"); | |
150 Utils.checkEmpty(map); | |
151 | |
175 this.luanLogger = luan.getLogger(LuceneIndex.class); | 152 this.luanLogger = luan.getLogger(LuceneIndex.class); |
176 this.key = key; | |
177 this.defaultFieldParser = defaultFieldParser; | 153 this.defaultFieldParser = defaultFieldParser; |
178 this.defaultFields = defaultFields; | 154 this.defaultFields = defaultFields; |
179 mfp = defaultFieldParser==null ? new MultiFieldParser() : new MultiFieldParser(defaultFieldParser,defaultFields); | 155 mfp = defaultFieldParser==null ? new MultiFieldParser() : new MultiFieldParser(defaultFieldParser,defaultFields); |
180 mfp.fields.put( "type", STRING_FIELD_PARSER ); | 156 mfp.fields.put( "type", STRING_FIELD_PARSER ); |
181 mfp.fields.put( "id", NumberFieldParser.LONG ); | 157 mfp.fields.put( "id", NumberFieldParser.LONG ); |
184 if( defaultFieldParser instanceof StringFieldParser ) { | 160 if( defaultFieldParser instanceof StringFieldParser ) { |
185 StringFieldParser sfp = (StringFieldParser)defaultFieldParser; | 161 StringFieldParser sfp = (StringFieldParser)defaultFieldParser; |
186 analyzer = sfp.analyzer; | 162 analyzer = sfp.analyzer; |
187 } | 163 } |
188 this.analyzer = analyzer; | 164 this.analyzer = analyzer; |
189 boolean wasCreated = reopen(); | 165 wasCreated = reopen(); |
190 if( postgresSpec == null ) { | 166 if( postgresSpec == null ) { |
191 postgresBackup = null; | 167 postgresBackup = null; |
192 } else { | 168 } else { |
193 if( completer == null ) | 169 if( completer == null ) |
194 throw new LuanException("completer is required for postgres_spec"); | 170 throw new LuanException("completer is required for postgres_spec"); |
195 Map spec = postgresSpec.asMap(); | 171 Map spec = postgresSpec.asMap(); |
196 postgresBackup = new PostgresBackup(luan,spec); | 172 postgresBackup = new PostgresBackup(luan,spec); |
197 if( postgresBackup != null ) { | 173 if( !wasCreated && postgresBackup.wasCreated ) { |
198 if( !wasCreated && postgresBackup.wasCreated ) { | 174 luanLogger.error("rebuilding postgres backup"); |
199 luanLogger.error("rebuilding postgres backup"); | 175 rebuild_postgres_backup(completer); |
200 rebuild_postgres_backup(completer); | 176 /* |
201 } else if( wasCreated && !postgresBackup.wasCreated ) { | 177 } else if( wasCreated && !postgresBackup.wasCreated ) { |
202 luanLogger.error("restoring from postgres"); | 178 luanLogger.error("restoring from postgres"); |
203 restore_from_postgres(); | 179 restore_from_postgres(); |
204 } | 180 */ |
205 } | 181 } |
206 } | 182 } |
183 luan.onClose(this); | |
184 } | |
185 | |
186 protected void finalize() throws Throwable { | |
187 if( !isClosed ) { | |
188 sysLogger.error("not closed",created); | |
189 close(); | |
190 } | |
191 super.finalize(); | |
207 } | 192 } |
208 | 193 |
209 public boolean reopen() throws IOException { | 194 public boolean reopen() throws IOException { |
210 IndexWriterConfig conf = new IndexWriterConfig(version,analyzer); | 195 IndexWriterConfig conf = new IndexWriterConfig(version,analyzer); |
211 snapshotDeletionPolicy = new SnapshotDeletionPolicy(conf.getIndexDeletionPolicy()); | 196 snapshotDeletionPolicy = new SnapshotDeletionPolicy(conf.getIndexDeletionPolicy()); |
447 | 432 |
448 public String to_string() { | 433 public String to_string() { |
449 return writer.getDirectory().toString(); | 434 return writer.getDirectory().toString(); |
450 } | 435 } |
451 | 436 |
452 private synchronized void close() throws IOException, SQLException { | 437 public synchronized void close() throws IOException { |
453 if( openCount > 0 ) { | 438 try { |
454 if( --openCount == 0 ) { | 439 doClose(); |
455 doClose(); | 440 } catch(SQLException e) { |
456 synchronized(indexes) { | 441 throw new RuntimeException(e); |
457 indexes.remove(key); | 442 } |
458 } | 443 isClosed = true; |
459 } | |
460 } | |
461 } | 444 } |
462 | 445 |
463 public void doClose() throws IOException, SQLException { | 446 public void doClose() throws IOException, SQLException { |
464 writer.close(); | 447 writer.close(); |
465 reader.close(); | 448 reader.close(); |
466 if( postgresBackup != null ) | 449 if( postgresBackup != null ) |
467 postgresBackup.close(); | 450 postgresBackup.close(); |
451 } | |
452 | |
453 private void closeWriter() throws IOException { | |
454 writeLock.lock(); | |
455 try { | |
456 writer.close(); | |
457 } finally { | |
458 writeLock.unlock(); | |
459 } | |
468 } | 460 } |
469 | 461 |
470 | 462 |
471 private static class DocFn extends LuanFunction { | 463 private static class DocFn extends LuanFunction { |
472 final IndexSearcher searcher; | 464 final IndexSearcher searcher; |
863 } | 855 } |
864 | 856 |
865 public void restore_from_postgres() | 857 public void restore_from_postgres() |
866 throws IOException, LuanException, SQLException | 858 throws IOException, LuanException, SQLException |
867 { | 859 { |
860 if( postgresBackup!=null && wasCreated && !postgresBackup.wasCreated ) { | |
861 luanLogger.error("restoring from postgres"); | |
862 force_restore_from_postgres(); | |
863 wasCreated = false; | |
864 } | |
865 } | |
866 | |
867 public void force_restore_from_postgres() | |
868 throws IOException, LuanException, SQLException | |
869 { | |
868 luanLogger.warn("start restore_from_postgres"); | 870 luanLogger.warn("start restore_from_postgres"); |
869 if( postgresBackup==null ) | 871 if( postgresBackup==null ) |
870 throw new NullPointerException(); | 872 throw new NullPointerException(); |
871 if( writeLock.isHeldByCurrentThread() ) | 873 if( writeLock.isHeldByCurrentThread() ) |
872 throw new RuntimeException(); | 874 throw new RuntimeException(); |