Merge lp:~tjoneslo/akiban-server/fix-bug-1172013 into lp:~akiban-technologies/akiban-server/trunk
- fix-bug-1172013
- Merge into trunk
Status: | Rejected |
---|---|
Rejected by: | Thomas Jones-Low |
Proposed branch: | lp:~tjoneslo/akiban-server/fix-bug-1172013 |
Merge into: | lp:~akiban-technologies/akiban-server/trunk |
Diff against target: |
1030 lines (+450/-101) 19 files modified
src/main/java/com/akiban/http/HttpConductorImpl.java (+8/-4) src/main/java/com/akiban/qp/persistitadapter/OperatorStore.java (+4/-3) src/main/java/com/akiban/rest/RestResponseBuilder.java (+0/-1) src/main/java/com/akiban/rest/resources/EntityResource.java (+3/-0) src/main/java/com/akiban/rest/resources/ModelResource.java (+4/-2) src/main/java/com/akiban/rest/resources/ResourceHelper.java (+9/-0) src/main/java/com/akiban/server/service/BackgroundWorkBase.java (+8/-7) src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java (+1/-1) src/main/java/com/akiban/server/service/dxl/HookableDDLFunctions.java (+0/-1) src/main/java/com/akiban/server/service/text/FullTextIndexService.java (+1/-1) src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java (+87/-52) src/main/java/com/akiban/server/store/PersistitStore.java (+13/-7) src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java (+1/-4) src/main/java/com/akiban/sql/aisddl/AISDDL.java (+1/-1) src/main/java/com/akiban/sql/aisddl/IndexDDL.java (+5/-11) src/main/java/com/akiban/sql/aisddl/TableDDL.java (+1/-2) src/test/java/com/akiban/server/rowdata/SchemaFactory.java (+1/-1) src/test/java/com/akiban/server/service/text/FullTextIndexServiceBug1172013IT.java (+296/-0) src/test/java/com/akiban/server/service/text/FullTextIndexServiceIT.java (+7/-3) |
To merge this branch: | bzr merge lp:~tjoneslo/akiban-server/fix-bug-1172013 |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Akiban Technologies | Pending | ||
Review via email: mp+163144@code.launchpad.net |
Commit message
Description of the change
Fix the w-w conflict in the testing system for the full text indexes. The testing has uncovered a problem which can (if circumstances are right) the end user too.
The core problem is the interaction of the delete index (which tries to delete the full text index) and the background thread populating the index. In order to get this to work correctly, I did two things. One, moved the point at which the index creation process calls the FT service to schedule the background process. Second, update the FT service to make the delete and populate aware of each other, so they are not stepping on each other.
BackgroundWorkBase - Update the internal set of background listeners from a HahsSet to a ConcurrentHashMap. Adding or removing listeners from different threads causes concurrent access exceptions at the worst possible time.
PersistitStore - This is where the FT service schedulePopulate now gets called. This in in the transaction to create the index itself, so the populate process gets flagged at the same time as the index creation, and doesn't if the index creation fails.
PersistitStoreS
IndexDDL - This is where previously the FT service sechedulePopulate was called. Since the only reason for the ServiceManager to be passed through to here was to get the FT Service, remove the now unused parameter. This has a cascade on the callers to remove the unused parameter as well.
FullTextIndexSe
Nathan Williams (nwilliams) wrote : | # |
Mike McMahon (mmcm) wrote : | # |
There is no semantic difference, but lines 81-87 of the diff could be just one switch on getIndexType(), I believe.
Unmerged revisions
- 2658. By tjoneslo
-
Update the FullTextIndexSe
rviceImpl code to handle the background task populating the full text indexes and managing the process of deleteing the index while the populate is going on. Plus test.
Preview Diff
1 | === modified file 'src/main/java/com/akiban/http/HttpConductorImpl.java' |
2 | --- src/main/java/com/akiban/http/HttpConductorImpl.java 2013-04-30 21:19:31 +0000 |
3 | +++ src/main/java/com/akiban/http/HttpConductorImpl.java 2013-05-09 13:22:31 +0000 |
4 | @@ -21,6 +21,7 @@ |
5 | import com.akiban.server.service.config.ConfigurationService; |
6 | import com.akiban.server.service.monitor.MonitorService; |
7 | import com.akiban.server.service.monitor.ServerMonitor; |
8 | +import com.akiban.server.service.monitor.SessionMonitor; |
9 | import com.akiban.server.service.security.SecurityService; |
10 | import com.akiban.server.service.session.Session; |
11 | import com.akiban.server.service.session.SessionService; |
12 | @@ -387,9 +388,9 @@ |
13 | ServerSessionMonitor sessionMonitor = new ServerSessionMonitor(SERVER_TYPE, |
14 | monitorService.allocateSessionId()); |
15 | |
16 | - conn.setAssociatedObject(sessionMonitor); |
17 | this.session = sessionService.createSession(); |
18 | monitorService.registerSessionMonitor(sessionMonitor, session); |
19 | + conn.setAssociatedObject(session); |
20 | return conn; |
21 | } |
22 | |
23 | @@ -397,10 +398,12 @@ |
24 | protected void connectionClosed(Connection connection) { |
25 | if (connection instanceof AsyncHttpConnection) { |
26 | AsyncHttpConnection conn = (AsyncHttpConnection)connection; |
27 | - ServerSessionMonitor monitor = (ServerSessionMonitor)conn.getAssociatedObject(); |
28 | + |
29 | + SessionMonitor monitor = monitorService.getSessionMonitor(session); |
30 | if (monitor != null) { |
31 | monitorService.deregisterSessionMonitor(monitor, session); |
32 | conn.setAssociatedObject(null); |
33 | + session.close(); |
34 | } |
35 | } |
36 | super.connectionClosed(connection); |
37 | @@ -420,9 +423,9 @@ |
38 | ServerSessionMonitor sessionMonitor = new ServerSessionMonitor(SERVER_TYPE, |
39 | monitorService.allocateSessionId()); |
40 | |
41 | - conn.setAssociatedObject(sessionMonitor); |
42 | this.session = sessionService.createSession(); |
43 | monitorService.registerSessionMonitor(sessionMonitor, session); |
44 | + conn.setAssociatedObject(session); |
45 | return conn; |
46 | } |
47 | |
48 | @@ -430,10 +433,11 @@ |
49 | protected void connectionClosed (Connection connection) { |
50 | if (connection instanceof SslConnection) { |
51 | AsyncHttpConnection conn = (AsyncHttpConnection)((SslConnection) connection).getSslEndPoint().getConnection(); |
52 | - ServerSessionMonitor monitor = (ServerSessionMonitor)conn.getAssociatedObject(); |
53 | + SessionMonitor monitor = monitorService.getSessionMonitor(session); |
54 | if (monitor != null) { |
55 | monitorService.deregisterSessionMonitor(monitor, session); |
56 | conn.setAssociatedObject(null); |
57 | + session.close(); |
58 | } |
59 | } |
60 | super.connectionClosed(connection); |
61 | |
62 | === modified file 'src/main/java/com/akiban/qp/persistitadapter/OperatorStore.java' |
63 | --- src/main/java/com/akiban/qp/persistitadapter/OperatorStore.java 2013-04-30 22:35:43 +0000 |
64 | +++ src/main/java/com/akiban/qp/persistitadapter/OperatorStore.java 2013-05-09 13:22:31 +0000 |
65 | @@ -18,6 +18,7 @@ |
66 | package com.akiban.qp.persistitadapter; |
67 | |
68 | import com.akiban.ais.model.*; |
69 | +import com.akiban.ais.model.Index.IndexType; |
70 | import com.akiban.qp.exec.UpdatePlannable; |
71 | import com.akiban.qp.exec.UpdateResult; |
72 | import com.akiban.qp.expression.IndexBound; |
73 | @@ -222,11 +223,11 @@ |
74 | |
75 | @Override |
76 | public void buildIndexes(Session session, Collection<? extends Index> indexes, boolean defer) { |
77 | - List<TableIndex> tableIndexes = new ArrayList<>(); |
78 | + List<Index> tableIndexes = new ArrayList<>(); |
79 | List<GroupIndex> groupIndexes = new ArrayList<>(); |
80 | for(Index index : indexes) { |
81 | - if(index.isTableIndex()) { |
82 | - tableIndexes.add((TableIndex)index); |
83 | + if(index.isTableIndex() || index.getIndexType() == IndexType.FULL_TEXT) { |
84 | + tableIndexes.add(index); |
85 | } |
86 | else if(index.isGroupIndex()) { |
87 | groupIndexes.add((GroupIndex)index); |
88 | |
89 | === modified file 'src/main/java/com/akiban/rest/RestResponseBuilder.java' |
90 | --- src/main/java/com/akiban/rest/RestResponseBuilder.java 2013-04-26 15:25:38 +0000 |
91 | +++ src/main/java/com/akiban/rest/RestResponseBuilder.java 2013-05-09 13:22:31 +0000 |
92 | @@ -128,7 +128,6 @@ |
93 | builder.append("\"}"); |
94 | } |
95 | |
96 | - |
97 | private String formatErrorWithJsonp(String code, String message) { |
98 | StringBuilder builder = new StringBuilder(); |
99 | if(isJsonp) { |
100 | |
101 | === modified file 'src/main/java/com/akiban/rest/resources/EntityResource.java' |
102 | --- src/main/java/com/akiban/rest/resources/EntityResource.java 2013-04-23 14:20:47 +0000 |
103 | +++ src/main/java/com/akiban/rest/resources/EntityResource.java 2013-05-09 13:22:31 +0000 |
104 | @@ -36,6 +36,9 @@ |
105 | import javax.ws.rs.core.MediaType; |
106 | import javax.ws.rs.core.Response; |
107 | import javax.ws.rs.core.UriInfo; |
108 | + |
109 | +import org.eclipse.jetty.server.Request; |
110 | + |
111 | import java.io.PrintWriter; |
112 | |
113 | import static com.akiban.rest.resources.ResourceHelper.IDENTIFIERS_MULTI; |
114 | |
115 | === modified file 'src/main/java/com/akiban/rest/resources/ModelResource.java' |
116 | --- src/main/java/com/akiban/rest/resources/ModelResource.java 2013-04-23 11:04:53 +0000 |
117 | +++ src/main/java/com/akiban/rest/resources/ModelResource.java 2013-05-09 13:22:31 +0000 |
118 | @@ -35,6 +35,8 @@ |
119 | import com.akiban.util.tap.InOutTap; |
120 | import com.akiban.util.tap.Tap; |
121 | import com.fasterxml.jackson.databind.JsonNode; |
122 | + |
123 | +import org.eclipse.jetty.server.Request; |
124 | import org.slf4j.Logger; |
125 | import org.slf4j.LoggerFactory; |
126 | |
127 | @@ -88,14 +90,14 @@ |
128 | @PathParam("schema") String schemaParam) { |
129 | final String schema = getSchemaName(request, schemaParam); |
130 | checkSchemaAccessible(reqs.securityService, request, schema); |
131 | + final Session session = (Session)request.getAttribute(Session.class.getName()); |
132 | return RestResponseBuilder |
133 | .forRequest(request) |
134 | .body(new RestResponseBuilder.BodyGenerator() { |
135 | @Override |
136 | public void write(PrintWriter writer) throws Exception { |
137 | MODEL_VIEW.in(); |
138 | - try (Session session = reqs.sessionService.createSession(); |
139 | - CloseableTransaction txn = reqs.transactionService.beginCloseableTransaction(session)) { |
140 | + try ( CloseableTransaction txn = reqs.transactionService.beginCloseableTransaction(session)) { |
141 | Space space = spaceForAIS(session, schema); |
142 | String json = space.toJson(); |
143 | writer.write(json); |
144 | |
145 | === modified file 'src/main/java/com/akiban/rest/resources/ResourceHelper.java' |
146 | --- src/main/java/com/akiban/rest/resources/ResourceHelper.java 2013-03-26 18:08:04 +0000 |
147 | +++ src/main/java/com/akiban/rest/resources/ResourceHelper.java 2013-05-09 13:22:31 +0000 |
148 | @@ -19,12 +19,16 @@ |
149 | |
150 | import com.akiban.ais.model.TableName; |
151 | import com.akiban.server.service.security.SecurityService; |
152 | +import com.akiban.server.service.session.Session; |
153 | |
154 | import javax.servlet.http.HttpServletRequest; |
155 | import javax.ws.rs.WebApplicationException; |
156 | import javax.ws.rs.core.MediaType; |
157 | import javax.ws.rs.core.Response; |
158 | import javax.ws.rs.core.UriInfo; |
159 | + |
160 | +import org.eclipse.jetty.server.Request; |
161 | + |
162 | import java.security.Principal; |
163 | |
164 | public class ResourceHelper { |
165 | @@ -61,6 +65,11 @@ |
166 | } |
167 | } |
168 | |
169 | + public static Session getSession (Request request) { |
170 | + Object obj = request.getConnection().getAssociatedObject(); |
171 | + assert obj instanceof Session; |
172 | + return (Session)obj; |
173 | + } |
174 | /** Expected to be used along with {@link #IDENTIFIERS_MULTI} */ |
175 | public static String getPKString(UriInfo uri) { |
176 | String pks[] = uri.getPath(false).split("/"); |
177 | |
178 | === modified file 'src/main/java/com/akiban/server/service/BackgroundWorkBase.java' |
179 | --- src/main/java/com/akiban/server/service/BackgroundWorkBase.java 2013-04-08 19:34:41 +0000 |
180 | +++ src/main/java/com/akiban/server/service/BackgroundWorkBase.java 2013-05-09 13:22:31 +0000 |
181 | @@ -18,12 +18,11 @@ |
182 | package com.akiban.server.service; |
183 | |
184 | import java.util.Collection; |
185 | -import java.util.HashSet; |
186 | -import java.util.Set; |
187 | +import java.util.concurrent.ConcurrentHashMap; |
188 | |
189 | public abstract class BackgroundWorkBase implements BackgroundWork<BackgroundObserver, BackgroundWork> |
190 | { |
191 | - private final Set<BackgroundObserver> observers = new HashSet<>(); |
192 | + private final ConcurrentHashMap<BackgroundObserver,Boolean> observers = new ConcurrentHashMap<>(); |
193 | |
194 | public BackgroundWorkBase() |
195 | { |
196 | @@ -34,7 +33,7 @@ |
197 | public void addObserver(BackgroundObserver observer) |
198 | { |
199 | // two observers are equal IFF they are the same object. |
200 | - observers.add(observer); |
201 | + observers.put(observer, true); |
202 | } |
203 | |
204 | @Override |
205 | @@ -45,19 +44,21 @@ |
206 | |
207 | public void removeObsevers(Collection<BackgroundObserver> os) |
208 | { |
209 | - observers.removeAll(os); |
210 | + for (BackgroundObserver key : os) { |
211 | + observers.remove(key); |
212 | + } |
213 | } |
214 | |
215 | @Override |
216 | public void removeAllObservers() |
217 | { |
218 | - observers.removeAll(observers); |
219 | + observers.clear(); |
220 | } |
221 | |
222 | @Override |
223 | public void notifyObservers() |
224 | { |
225 | - for (BackgroundObserver o : observers) |
226 | + for (BackgroundObserver o : observers.keySet()) |
227 | o.update(this); |
228 | } |
229 | } |
230 | |
231 | === modified file 'src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java' |
232 | --- src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-04-22 02:00:55 +0000 |
233 | +++ src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-05-09 13:22:31 +0000 |
234 | @@ -959,8 +959,8 @@ |
235 | // Cannot use Index.getAllTableIDs(), stub AIS only has to be name-correct |
236 | for(Index index : indexesToAdd) { |
237 | switch(index.getIndexType()) { |
238 | + case FULL_TEXT: // TODO: More IDs? |
239 | case TABLE: |
240 | - case FULL_TEXT: // TODO: More IDs? |
241 | UserTable table = ais.getUserTable(index.getIndexName().getFullTableName()); |
242 | if(table != null) { |
243 | tableIDs.add(table.getTableId()); |
244 | |
245 | === modified file 'src/main/java/com/akiban/server/service/dxl/HookableDDLFunctions.java' |
246 | --- src/main/java/com/akiban/server/service/dxl/HookableDDLFunctions.java 2013-04-11 00:05:29 +0000 |
247 | +++ src/main/java/com/akiban/server/service/dxl/HookableDDLFunctions.java 2013-05-09 13:22:31 +0000 |
248 | @@ -39,7 +39,6 @@ |
249 | |
250 | import static com.akiban.ais.util.TableChangeValidator.ChangeLevel; |
251 | import static com.akiban.util.Exceptions.throwAlways; |
252 | -import static com.akiban.util.Exceptions.throwIfInstanceOf; |
253 | |
254 | public final class HookableDDLFunctions implements DDLFunctions { |
255 | |
256 | |
257 | === modified file 'src/main/java/com/akiban/server/service/text/FullTextIndexService.java' |
258 | --- src/main/java/com/akiban/server/service/text/FullTextIndexService.java 2013-04-22 18:37:21 +0000 |
259 | +++ src/main/java/com/akiban/server/service/text/FullTextIndexService.java 2013-05-09 13:22:31 +0000 |
260 | @@ -35,7 +35,7 @@ |
261 | * created. |
262 | * @param name |
263 | */ |
264 | - public void schedulePopulate(String schema, String table, String index); |
265 | + public void schedulePopulate(Session session, IndexName name); |
266 | |
267 | /** |
268 | * Update the given index based on the changedRow |
269 | |
270 | === modified file 'src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java' |
271 | --- src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java 2013-04-29 15:59:33 +0000 |
272 | +++ src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java 2013-05-09 13:22:31 +0000 |
273 | @@ -34,6 +34,7 @@ |
274 | import com.akiban.qp.rowtype.HKeyRowType; |
275 | import com.akiban.qp.util.HKeyCache; |
276 | import com.akiban.server.error.AkibanInternalException; |
277 | +import com.akiban.server.error.QueryCanceledException; |
278 | import com.akiban.server.service.BackgroundWork; |
279 | import com.akiban.server.service.BackgroundWorkBase; |
280 | import com.akiban.server.service.Service; |
281 | @@ -47,6 +48,7 @@ |
282 | import com.akiban.server.store.PersistitStore; |
283 | import com.akiban.server.store.PersistitStore.HKeyBytesStream; |
284 | import com.akiban.server.store.Store; |
285 | +import com.akiban.server.types3.mcompat.mfuncs.WaitFunctionHelpers; |
286 | |
287 | import org.apache.lucene.index.IndexWriter; |
288 | import org.apache.lucene.search.Query; |
289 | @@ -64,6 +66,7 @@ |
290 | import java.util.List; |
291 | import java.util.Timer; |
292 | import java.util.TimerTask; |
293 | +import java.util.concurrent.ConcurrentHashMap; |
294 | |
295 | |
296 | public class FullTextIndexServiceImpl extends FullTextIndexInfosImpl implements FullTextIndexService, Service { |
297 | @@ -92,7 +95,8 @@ |
298 | |
299 | private volatile Timer populateTimer; |
300 | private long populateDelayInterval; |
301 | - |
302 | + private ConcurrentHashMap<IndexName,Session> populating; |
303 | + |
304 | private static final Logger logger = LoggerFactory.getLogger(FullTextIndexServiceImpl.class); |
305 | |
306 | @Inject |
307 | @@ -105,6 +109,7 @@ |
308 | this.store = store; |
309 | this.transactionService = transactionService; |
310 | this.treeService = treeService; |
311 | + this.populating = new ConcurrentHashMap<> (); |
312 | |
313 | } |
314 | |
315 | @@ -140,8 +145,24 @@ |
316 | |
317 | @Override |
318 | public void dropIndex(Session session, FullTextIndex idx) { |
319 | - // delete 'promise' for population, if any |
320 | - deleteFromTree(session, idx.getIndexName()); |
321 | + |
322 | + logger.error("Delete {}", idx.getIndexName()); |
323 | + |
324 | + Session populatingSession = populating.putIfAbsent(idx.getIndexName(), session); |
325 | + if (populatingSession != null) { |
326 | + // if the population process is running, cancel it |
327 | + populatingSession.cancelCurrentQuery(true); |
328 | + // wait for the thread to complete |
329 | + try { |
330 | + WaitFunctionHelpers.waitOn(getBackgroundWorks()); |
331 | + } catch (InterruptedException e) { |
332 | + ;// TODO: do nothing |
333 | + } |
334 | + } else { |
335 | + // delete 'promise' for population, if any |
336 | + deleteFromTree(session, idx.getIndexName()); |
337 | + populating.remove(idx.getIndexName()); |
338 | + } |
339 | |
340 | // delete documents |
341 | FullTextIndexInfo idxInfo = getIndex(session, idx.getIndexName(), idx.getIndexedTable().getAIS()); |
342 | @@ -149,6 +170,7 @@ |
343 | synchronized (indexes) { |
344 | indexes.remove(idx.getIndexName()); |
345 | } |
346 | + |
347 | } |
348 | |
349 | @Override |
350 | @@ -321,33 +343,26 @@ |
351 | |
352 | |
353 | @Override |
354 | - public void schedulePopulate(String schema, String table, String index) |
355 | + public void schedulePopulate(Session session, IndexName name) |
356 | { |
357 | - Session session = sessionService.createSession(); |
358 | - boolean success = false; |
359 | + logger.debug("Scheduled populate {}", name.toString()); |
360 | + |
361 | try |
362 | { |
363 | - transactionService.beginTransaction(session); |
364 | - if(addPopulate(session, schema, table, index) && !hasScheduled && populateEnabled) |
365 | - { |
366 | - populateTimer.schedule(populateWorker(), populateDelayInterval); |
367 | - hasScheduled = true; |
368 | + // Add the index to the list (in persisit) of indexes to build |
369 | + addPopulate(session, name); |
370 | + |
371 | + // if there are no scheduled populate workers running, |
372 | + // add one to run shortly. |
373 | + if (populateEnabled && !hasScheduled) { |
374 | + populateTimer.schedule(populateWorker(), populateDelayInterval); |
375 | + hasScheduled = true; |
376 | } |
377 | - |
378 | - success = true; |
379 | } |
380 | catch (PersistitException ex) |
381 | { |
382 | throw new AkibanInternalException("Error while scheduling index population", ex); |
383 | } |
384 | - finally |
385 | - { |
386 | - if (success) |
387 | - transactionService.commitTransaction(session); |
388 | - else |
389 | - transactionService.rollbackTransaction(session); |
390 | - session.close(); |
391 | - } |
392 | } |
393 | |
394 | private final List<? extends BackgroundWork> backgroundWorks |
395 | @@ -457,26 +472,45 @@ |
396 | |
397 | |
398 | //----------- private helpers ----------- |
399 | - private synchronized void runPopulate() |
400 | + protected boolean populateNextIndex(Session session) throws PersistitException |
401 | + { |
402 | + IndexName toPopulate = null; |
403 | + transactionService.beginTransaction(session); |
404 | + Exchange ex = null; |
405 | + try { |
406 | + ex = getPopulateExchange(session); |
407 | + |
408 | + toPopulate = nextInQueue(session, ex, false); |
409 | + if (toPopulate != null && stillExists (session, toPopulate)) { |
410 | + createIndex(session, toPopulate); |
411 | + ex.remove(); |
412 | + transactionService.commitTransaction(session); |
413 | + populating.remove(toPopulate); |
414 | + return true; |
415 | + } |
416 | + } catch (QueryCanceledException e) { |
417 | + // The query could be canceled if the user drops the index |
418 | + // while this thread is populating the index |
419 | + // Clean up after ourselves. |
420 | + if (ex != null) ex.remove(); |
421 | + populating.remove(toPopulate); |
422 | + transactionService.commitTransaction(session); |
423 | + // start another thread to make sure we're not missing anything |
424 | + populateTimer.schedule(populateWorker(), populateDelayInterval); |
425 | + hasScheduled = true; |
426 | + } finally { |
427 | + transactionService.rollbackTransactionIfOpen(session); |
428 | + } |
429 | + return false; |
430 | + } |
431 | + |
432 | + protected synchronized void runPopulate() |
433 | { |
434 | populateRunning = true; |
435 | Session session = sessionService.createSession(); |
436 | - boolean transaction = true; |
437 | try |
438 | { |
439 | - transactionService.beginTransaction(session); |
440 | - Exchange ex = getPopulateExchange(session); |
441 | - IndexName toPopulate; |
442 | - while ((toPopulate = nextInQueue(ex)) != null) |
443 | - { |
444 | - if (stillExists(session, toPopulate)) |
445 | - createIndex(session, toPopulate); |
446 | - else |
447 | - logger.debug("FullTextIndex " + toPopulate + " deleted before population"); |
448 | - } |
449 | - ex.removeAll(); |
450 | - hasScheduled = false; |
451 | - transaction = false; |
452 | + while (populateNextIndex(session)) {} |
453 | } |
454 | catch (PersistitException ex1) |
455 | { |
456 | @@ -484,11 +518,7 @@ |
457 | } |
458 | finally |
459 | { |
460 | - if (transaction) |
461 | - transactionService.rollbackTransaction(session); |
462 | - else |
463 | - transactionService.commitTransaction(session); |
464 | - session.close(); |
465 | + hasScheduled = false; |
466 | backgroundWorks.get(populateWork).notifyObservers(); |
467 | populateRunning = false; |
468 | } |
469 | @@ -595,20 +625,28 @@ |
470 | return new DefaultPopulateWorker(); |
471 | } |
472 | |
473 | - protected IndexName nextInQueue(Exchange ex) throws PersistitException |
474 | + protected IndexName nextInQueue(Session session, Exchange ex, boolean traversing) throws PersistitException |
475 | { |
476 | Key key = ex.getKey(); |
477 | |
478 | - if (ex.next(true)) // empty tree? |
479 | + while (ex.next(true)) |
480 | { |
481 | key.reset(); |
482 | IndexName ret = new IndexName(new TableName(key.decodeString(), |
483 | key.decodeString()), |
484 | key.decodeString()); |
485 | + // The populating map contains the indexes currently being built |
486 | + // if this name is already in the tree, skip this one, and try |
487 | + // the next. |
488 | + if (!traversing) { |
489 | + if (populating.putIfAbsent(ret, session) != null) { |
490 | + continue; |
491 | + } |
492 | + } |
493 | + |
494 | return ret; |
495 | } |
496 | - else |
497 | - return null; |
498 | + return null; |
499 | } |
500 | |
501 | protected Exchange getPopulateExchange(Session session) throws PersistitException |
502 | @@ -624,10 +662,7 @@ |
503 | private volatile boolean hasScheduled = false; |
504 | private volatile boolean populateEnabled = false; |
505 | |
506 | - private synchronized boolean addPopulate(Session session, |
507 | - String schema, |
508 | - String table, |
509 | - String index) throws PersistitException |
510 | + private synchronized boolean addPopulate(Session session, IndexName name) throws PersistitException |
511 | { |
512 | Exchange ex = getPopulateExchange(session); |
513 | |
514 | @@ -635,9 +670,9 @@ |
515 | // (Because they should have been removed in dropIndex()) |
516 | // KEY: schema | table | indexName |
517 | ex.getKey().clear() |
518 | - .append(schema) |
519 | - .append(table) |
520 | - .append(index); |
521 | + .append(name.getSchemaName()) |
522 | + .append(name.getTableName()) |
523 | + .append(name.getName()); |
524 | |
525 | // VALUE: <empty> |
526 | |
527 | |
528 | === modified file 'src/main/java/com/akiban/server/store/PersistitStore.java' |
529 | --- src/main/java/com/akiban/server/store/PersistitStore.java 2013-05-03 00:59:49 +0000 |
530 | +++ src/main/java/com/akiban/server/store/PersistitStore.java 2013-05-09 13:22:31 +0000 |
531 | @@ -1824,14 +1824,20 @@ |
532 | Map<Integer,RowDef> userRowDefs = new HashMap<>(); |
533 | Set<Index> indexesToBuild = new HashSet<>(); |
534 | for(Index index : indexes) { |
535 | - IndexDef indexDef = index.indexDef(); |
536 | - if(indexDef == null) { |
537 | - throw new IllegalArgumentException("indexDef was null for index: " + index); |
538 | + if (index.getIndexType() == IndexType.FULL_TEXT) { |
539 | + // This schedules a deferred process to populate the |
540 | + // full text index at a later date (starting in a few seconds). |
541 | + fullTextService.schedulePopulate(session, index.getIndexName()); |
542 | + } else { |
543 | + IndexDef indexDef = index.indexDef(); |
544 | + if(indexDef == null) { |
545 | + throw new IllegalArgumentException("indexDef was null for index: " + index); |
546 | + } |
547 | + indexesToBuild.add(index); |
548 | + RowDef rowDef = indexDef.getRowDef(); |
549 | + userRowDefs.put(rowDef.getRowDefId(), rowDef); |
550 | + groups.add(rowDef.table().getGroup()); |
551 | } |
552 | - indexesToBuild.add(index); |
553 | - RowDef rowDef = indexDef.getRowDef(); |
554 | - userRowDefs.put(rowDef.getRowDefId(), rowDef); |
555 | - groups.add(rowDef.table().getGroup()); |
556 | } |
557 | PersistitIndexRowBuffer indexRow = new PersistitIndexRowBuffer(adapter(session)); |
558 | for (Group group : groups) { |
559 | |
560 | === modified file 'src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java' |
561 | --- src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java 2013-04-11 18:35:20 +0000 |
562 | +++ src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java 2013-05-09 13:22:31 +0000 |
563 | @@ -389,10 +389,7 @@ |
564 | if(keepTree) { |
565 | newIndex.setTreeName(proposed.getTreeName()); |
566 | } |
567 | - if (newIndex.getIndexType() != Index.IndexType.FULL_TEXT) { |
568 | - // TODO: For now, do not build. |
569 | - newIndexes.add(newIndex); |
570 | - } |
571 | + newIndexes.add(newIndex); |
572 | tableIDs.addAll(newIndex.getAllTableIDs()); |
573 | schemas.add(DefaultNameGenerator.schemaNameForIndex(newIndex)); |
574 | } |
575 | |
576 | === modified file 'src/main/java/com/akiban/sql/aisddl/AISDDL.java' |
577 | --- src/main/java/com/akiban/sql/aisddl/AISDDL.java 2013-03-27 04:42:10 +0000 |
578 | +++ src/main/java/com/akiban/sql/aisddl/AISDDL.java 2013-05-09 13:22:31 +0000 |
579 | @@ -84,7 +84,7 @@ |
580 | server.getBinderContext(), context); |
581 | return; |
582 | case NodeTypes.CREATE_INDEX_NODE: |
583 | - IndexDDL.createIndex(ddlFunctions, session, schema, (CreateIndexNode)ddl, server.getServiceManager()); |
584 | + IndexDDL.createIndex(ddlFunctions, session, schema, (CreateIndexNode)ddl); |
585 | return; |
586 | case NodeTypes.DROP_INDEX_NODE: |
587 | IndexDDL.dropIndex(ddlFunctions, session, schema, (DropIndexNode)ddl, context); |
588 | |
589 | === modified file 'src/main/java/com/akiban/sql/aisddl/IndexDDL.java' |
590 | --- src/main/java/com/akiban/sql/aisddl/IndexDDL.java 2013-04-15 17:21:44 +0000 |
591 | +++ src/main/java/com/akiban/sql/aisddl/IndexDDL.java 2013-05-09 13:22:31 +0000 |
592 | @@ -36,8 +36,6 @@ |
593 | import com.akiban.server.service.session.Session; |
594 | |
595 | import com.akiban.qp.operator.QueryContext; |
596 | -import com.akiban.server.service.ServiceManager; |
597 | -import com.akiban.server.service.text.FullTextIndexService; |
598 | |
599 | /** DDL operations on Indices */ |
600 | public class IndexDDL |
601 | @@ -150,18 +148,17 @@ |
602 | public static void createIndex(DDLFunctions ddlFunctions, |
603 | Session session, |
604 | String defaultSchemaName, |
605 | - CreateIndexNode createIndex, |
606 | - ServiceManager sm) { |
607 | + CreateIndexNode createIndex) { |
608 | AkibanInformationSchema ais = ddlFunctions.getAIS(session); |
609 | |
610 | Collection<Index> indexesToAdd = new LinkedList<>(); |
611 | |
612 | - indexesToAdd.add(buildIndex(ais, defaultSchemaName, createIndex, sm)); |
613 | + indexesToAdd.add(buildIndex(ais, defaultSchemaName, createIndex)); |
614 | |
615 | ddlFunctions.createIndexes(session, indexesToAdd); |
616 | } |
617 | |
618 | - protected static Index buildIndex (AkibanInformationSchema ais, String defaultSchemaName, CreateIndexNode index, ServiceManager sm) { |
619 | + protected static Index buildIndex (AkibanInformationSchema ais, String defaultSchemaName, CreateIndexNode index){ |
620 | final String schemaName = index.getObjectName().getSchemaName() != null ? index.getObjectName().getSchemaName() : defaultSchemaName; |
621 | final String indexName = index.getObjectName().getTableName(); |
622 | |
623 | @@ -176,7 +173,7 @@ |
624 | |
625 | if (index.getColumnList().functionType() == IndexColumnList.FunctionType.FULL_TEXT) { |
626 | logger.debug ("Building Full text index on table {}", tableName) ; |
627 | - tableIndex = buildFullTextIndex (builder, tableName, indexName, index, sm); |
628 | + tableIndex = buildFullTextIndex (builder, tableName, indexName, index); |
629 | } else if (checkIndexType (index, tableName) == Index.IndexType.TABLE) { |
630 | logger.debug ("Building Table index on table {}", tableName) ; |
631 | tableIndex = buildTableIndex (builder, tableName, indexName, index); |
632 | @@ -331,9 +328,8 @@ |
633 | return builder.akibanInformationSchema().getGroup(groupName).getIndex(indexName); |
634 | } |
635 | |
636 | - protected static Index buildFullTextIndex (AISBuilder builder, TableName tableName, String indexName, IndexDefinition index, ServiceManager sm) { |
637 | + protected static Index buildFullTextIndex (AISBuilder builder, TableName tableName, String indexName, IndexDefinition index) { |
638 | UserTable table = builder.akibanInformationSchema().getUserTable(tableName); |
639 | - FullTextIndexService fullTextService = sm.getServiceByClass(FullTextIndexService.class); |
640 | |
641 | if (index.getJoinType() != null) { |
642 | throw new TableIndexJoinTypeException(); |
643 | @@ -367,8 +363,6 @@ |
644 | } |
645 | |
646 | builder.fullTextIndexColumn(tableName, indexName, schemaName, columnTable.getTableName(), columnName, i); |
647 | - // populate index |
648 | - fullTextService.schedulePopulate(schemaName, tableName.getTableName(), indexName); |
649 | i++; |
650 | } |
651 | return builder.akibanInformationSchema().getUserTable(tableName).getFullTextIndex(indexName); |
652 | |
653 | === modified file 'src/main/java/com/akiban/sql/aisddl/TableDDL.java' |
654 | --- src/main/java/com/akiban/sql/aisddl/TableDDL.java 2013-04-28 04:20:16 +0000 |
655 | +++ src/main/java/com/akiban/sql/aisddl/TableDDL.java 2013-05-09 13:22:31 +0000 |
656 | @@ -48,7 +48,6 @@ |
657 | import com.akiban.sql.parser.ConstraintDefinitionNode; |
658 | import com.akiban.sql.parser.CreateTableNode; |
659 | import com.akiban.sql.parser.CurrentDatetimeOperatorNode; |
660 | -import com.akiban.sql.parser.DefaultNode; |
661 | import com.akiban.sql.parser.DropGroupNode; |
662 | import com.akiban.sql.parser.DropTableNode; |
663 | import com.akiban.sql.parser.ExistenceCheck; |
664 | @@ -487,7 +486,7 @@ |
665 | |
666 | if (columnList.functionType() == IndexColumnList.FunctionType.FULL_TEXT) { |
667 | logger.debug ("Building Full text index on table {}", table.getName()) ; |
668 | - tableIndex = IndexDDL.buildFullTextIndex (builder, table.getName(), indexName, id, context.getServiceManager()); |
669 | + tableIndex = IndexDDL.buildFullTextIndex (builder, table.getName(), indexName, id); |
670 | } else if (IndexDDL.checkIndexType (id, table.getName()) == Index.IndexType.TABLE) { |
671 | logger.debug ("Building Table index on table {}", table.getName()) ; |
672 | tableIndex = IndexDDL.buildTableIndex (builder, table.getName(), indexName, id); |
673 | |
674 | === modified file 'src/test/java/com/akiban/server/rowdata/SchemaFactory.java' |
675 | --- src/test/java/com/akiban/server/rowdata/SchemaFactory.java 2013-04-15 16:20:25 +0000 |
676 | +++ src/test/java/com/akiban/server/rowdata/SchemaFactory.java 2013-05-09 13:22:31 +0000 |
677 | @@ -125,7 +125,7 @@ |
678 | if (stmt instanceof CreateTableNode) { |
679 | TableDDL.createTable(ddlFunctions , session , defaultSchema, (CreateTableNode) stmt, null); |
680 | } else if (stmt instanceof CreateIndexNode) { |
681 | - IndexDDL.createIndex(ddlFunctions, session, defaultSchema, (CreateIndexNode) stmt, sm); |
682 | + IndexDDL.createIndex(ddlFunctions, session, defaultSchema, (CreateIndexNode) stmt); |
683 | } else if (stmt instanceof CreateViewNode) { |
684 | ViewDDL.createView(ddlFunctions, session, defaultSchema, (CreateViewNode) stmt, |
685 | new AISBinderContext(ddlFunctions.getAIS(session), defaultSchema), null); |
686 | |
687 | === added file 'src/test/java/com/akiban/server/service/text/FullTextIndexServiceBug1172013IT.java' |
688 | --- src/test/java/com/akiban/server/service/text/FullTextIndexServiceBug1172013IT.java 1970-01-01 00:00:00 +0000 |
689 | +++ src/test/java/com/akiban/server/service/text/FullTextIndexServiceBug1172013IT.java 2013-05-09 13:22:31 +0000 |
690 | @@ -0,0 +1,296 @@ |
691 | +/** |
692 | + * Copyright (C) 2009-2013 Akiban Technologies, Inc. |
693 | + * |
694 | + * This program is free software: you can redistribute it and/or modify |
695 | + * it under the terms of the GNU Affero General Public License as published by |
696 | + * the Free Software Foundation, either version 3 of the License, or |
697 | + * (at your option) any later version. |
698 | + * |
699 | + * This program is distributed in the hope that it will be useful, |
700 | + * but WITHOUT ANY WARRANTY; without even the implied warranty of |
701 | + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
702 | + * GNU Affero General Public License for more details. |
703 | + * |
704 | + * You should have received a copy of the GNU Affero General Public License |
705 | + * along with this program. If not, see <http://www.gnu.org/licenses/>. |
706 | + */ |
707 | +package com.akiban.server.service.text; |
708 | + |
709 | +import static org.junit.Assert.assertEquals; |
710 | +import static org.junit.Assert.assertTrue; |
711 | +import java.sql.Connection; |
712 | +import java.sql.DriverManager; |
713 | +import java.sql.SQLException; |
714 | + |
715 | +import org.junit.Before; |
716 | +import org.junit.Test; |
717 | + |
718 | +import org.slf4j.Logger; |
719 | +import org.slf4j.LoggerFactory; |
720 | + |
721 | +import com.akiban.ais.model.IndexName; |
722 | +import com.akiban.ais.model.TableName; |
723 | +import com.akiban.qp.operator.QueryContext; |
724 | +import com.akiban.qp.persistitadapter.PersistitAdapter; |
725 | +import com.akiban.qp.rowtype.Schema; |
726 | +import com.akiban.qp.util.SchemaCache; |
727 | +import com.akiban.server.error.DuplicateIndexColumnException; |
728 | +import com.akiban.server.error.DuplicateIndexException; |
729 | +import com.akiban.server.service.servicemanager.GuicedServiceManager; |
730 | +import com.akiban.server.service.session.Session; |
731 | +import com.akiban.server.service.session.SessionServiceImpl; |
732 | +import com.akiban.server.test.it.ITBase; |
733 | +import com.akiban.server.types3.mcompat.mfuncs.WaitFunctionHelpers; |
734 | +import com.akiban.sql.embedded.EmbeddedJDBCService; |
735 | +import com.akiban.sql.embedded.EmbeddedJDBCServiceImpl; |
736 | +import com.persistit.Exchange; |
737 | +import com.persistit.exception.PersistitException; |
738 | + |
739 | +public class FullTextIndexServiceBug1172013IT extends ITBase { |
740 | + public static final String SCHEMA = "test"; |
741 | + protected FullTextIndexService fullText; |
742 | + protected Schema schema; |
743 | + protected PersistitAdapter adapter; |
744 | + protected QueryContext queryContext; |
745 | + private int c; |
746 | + private int o; |
747 | + private int i; |
748 | + private int a; |
749 | + private static final Logger logger = LoggerFactory.getLogger(FullTextIndexServiceBug1172013IT.class); |
750 | + |
751 | + @Override |
752 | + protected GuicedServiceManager.BindingsConfigurationProvider serviceBindingsProvider() { |
753 | + return super.serviceBindingsProvider() |
754 | + .bindAndRequire(FullTextIndexService.class, FullTextIndexServiceImpl.class) |
755 | + .bindAndRequire(EmbeddedJDBCService.class, EmbeddedJDBCServiceImpl.class); |
756 | + } |
757 | + |
758 | + @Before |
759 | + public void createData() { |
760 | + c = createTable(SCHEMA, "c", |
761 | + "cid INT PRIMARY KEY NOT NULL", |
762 | + "name VARCHAR(128) COLLATE en_us_ci"); |
763 | + o = createTable(SCHEMA, "o", |
764 | + "oid INT PRIMARY KEY NOT NULL", |
765 | + "cid INT NOT NULL", |
766 | + "c1 VARCHAR(128) COLLATE en_us_ci", |
767 | + "c2 VARCHAR(128) COLLATE en_us_ci", |
768 | + "c3 VARCHAR(128) COLLATE en_us_ci", |
769 | + "c4 VARCHAR(128) COLLATE en_us_ci", |
770 | + "GROUPING FOREIGN KEY(cid) REFERENCES c(cid)", |
771 | + "order_date DATE"); |
772 | + i = createTable(SCHEMA, "i", |
773 | + "iid INT PRIMARY KEY NOT NULL", |
774 | + "oid INT NOT NULL", |
775 | + "GROUPING FOREIGN KEY(oid) REFERENCES o(oid)", |
776 | + "sku VARCHAR(10) NOT NULL"); |
777 | + a = createTable(SCHEMA, "a", |
778 | + "aid INT PRIMARY KEY NOT NULL", |
779 | + "cid INT NOT NULL", |
780 | + "GROUPING FOREIGN KEY(cid) REFERENCES c(cid)", |
781 | + "state CHAR(2)"); |
782 | + writeRow(c, 1, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices justo in sapien ullamcorper eu mattis massa pretium."); |
783 | + writeRow(o, 101, 1, "c1", "c2", "c3", "c4", "2012-12-12"); |
784 | + writeRow(i, 10101, 101, "ABCD"); |
785 | + writeRow(i, 10102, 101, "1234"); |
786 | + writeRow(o, 102, 1, "c1", "c2", "c3", "c4","2013-01-01"); |
787 | + writeRow(a, 101, 1, "MA"); |
788 | + writeRow(c, 2, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices justo in sapien ullamcorper eu mattis massa pretium."); |
789 | + writeRow(a, 201, 2, "NY"); |
790 | + writeRow(c, 3, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam ultrices justo in sapien ullamcorper eu mattis massa pretium."); |
791 | + writeRow(o, 301, 3, "c1", "c2", "c3", "c4", "2010-04-01"); |
792 | + writeRow(a, 301, 3, "MA"); |
793 | + writeRow(a, 302, 3, "ME"); |
794 | + |
795 | + fullText = serviceManager().getServiceByClass(FullTextIndexService.class); |
796 | + |
797 | + schema = SchemaCache.globalSchema(ais()); |
798 | + adapter = persistitAdapter(schema); |
799 | + queryContext = queryContext(adapter); |
800 | + } |
801 | + |
802 | + @Test |
803 | + public void testDelete1 () throws InterruptedException, PersistitException { |
804 | + logger.error("Running test delete 1"); |
805 | + // This test is specifically for FullTextIndexServiceImpl.java |
806 | + assertEquals(FullTextIndexServiceImpl.class, fullText.getClass()); |
807 | + FullTextIndexServiceImpl fullTextImpl = (FullTextIndexServiceImpl)fullText; |
808 | + |
809 | + // disable the populate worker (so it doesn't read all the entries |
810 | + // out before we get a chance to look at the tree. |
811 | + createFullTextIndex(serviceManager(), |
812 | + SCHEMA, "o", "idx3_o", |
813 | + "oid", "c1", "c2", "c3", "c4"); |
814 | + //fullTextImpl.getBackgroundWorks().get(0).forceExecution(); |
815 | + //WaitFunctionHelpers.waitOn(fullText.getBackgroundWorks()); |
816 | + |
817 | + new Thread(new DropIndex()).start(); |
818 | + |
819 | + try { |
820 | + createFullTextIndex(serviceManager(), |
821 | + SCHEMA, "o", "idx3_o", |
822 | + "oid", "c1", "c2", "c3", "c4"); |
823 | + } catch (DuplicateIndexException ex) { |
824 | + logger.error("Got Duplicate Index"); |
825 | + ; // an expected possible outcome. |
826 | + } catch (DuplicateIndexColumnException ex) { |
827 | + logger.error("Got Duplicate Column"); |
828 | + ; // an expected possible outcome |
829 | + } |
830 | + |
831 | + WaitFunctionHelpers.waitOn(fullText.getBackgroundWorks()); |
832 | + |
833 | + traverse(fullTextImpl, |
834 | + new Visitor() |
835 | + { |
836 | + int n = 0; |
837 | + |
838 | + @Override |
839 | + public void visit(IndexName idx) |
840 | + { |
841 | + ++n; |
842 | + } |
843 | + |
844 | + @Override |
845 | + public void endOfTree() |
846 | + { |
847 | + assertEquals (0, n); |
848 | + } |
849 | + }); |
850 | + |
851 | + } |
852 | + |
853 | + @Test |
854 | + public void testDelete2() throws InterruptedException, PersistitException { |
855 | + logger.error("Running test delete 2"); |
856 | + // This test is specifically for FullTextIndexServiceImpl.java |
857 | + assertEquals(FullTextIndexServiceImpl.class, fullText.getClass()); |
858 | + FullTextIndexServiceImpl fullTextImpl = (FullTextIndexServiceImpl)fullText; |
859 | + |
860 | + createFullTextIndex(serviceManager(), |
861 | + SCHEMA, "o", "idx3_o", |
862 | + "oid", "c1", "c2", "c3", "c4"); |
863 | + fullTextImpl.getBackgroundWorks().get(0).forceExecution(); |
864 | + WaitFunctionHelpers.waitOn(fullText.getBackgroundWorks()); |
865 | + |
866 | + new Thread(new DropIndex()).start(); |
867 | + |
868 | + try { |
869 | + createFullTextIndex(serviceManager(), |
870 | + SCHEMA, "o", "idx3_o", |
871 | + "oid", "c1", "c2", "c3", "c4"); |
872 | + } catch (DuplicateIndexException ex) { |
873 | + logger.error("Got Duplicate Index"); |
874 | + ; // an expected possible outcome. |
875 | + } catch (DuplicateIndexColumnException ex) { |
876 | + logger.error("Got Duplicate Column"); |
877 | + ; // an expected possible outcome |
878 | + } |
879 | + |
880 | + WaitFunctionHelpers.waitOn(fullText.getBackgroundWorks()); |
881 | + |
882 | + traverse(fullTextImpl, |
883 | + new Visitor() |
884 | + { |
885 | + int n = 0; |
886 | + |
887 | + @Override |
888 | + public void visit(IndexName idx) |
889 | + { |
890 | + ++n; |
891 | + } |
892 | + |
893 | + @Override |
894 | + public void endOfTree() |
895 | + { |
896 | + assertEquals (0, n); |
897 | + } |
898 | + }); |
899 | + |
900 | + |
901 | + } |
902 | + |
903 | + @Test |
904 | + public void testDelete3() throws InterruptedException, PersistitException { |
905 | + logger.error("Running test delete 3"); |
906 | + // This test is specifically for FullTextIndexServiceImpl.java |
907 | + assertEquals(FullTextIndexServiceImpl.class, fullText.getClass()); |
908 | + FullTextIndexServiceImpl fullTextImpl = (FullTextIndexServiceImpl)fullText; |
909 | + |
910 | + createFullTextIndex(serviceManager(), |
911 | + SCHEMA, "o", "idx3_o", |
912 | + "oid", "c1", "c2", "c3", "c4"); |
913 | + fullTextImpl.getBackgroundWorks().get(0).forceExecution(); |
914 | + //WaitFunctionHelpers.waitOn(fullText.getBackgroundWorks()); |
915 | + |
916 | + deleteFullTextIndex(serviceManager(), new IndexName(new TableName(SCHEMA, "o"), "idx3_o")); |
917 | + |
918 | + WaitFunctionHelpers.waitOn(fullText.getBackgroundWorks()); |
919 | + |
920 | + traverse(fullTextImpl, |
921 | + new Visitor() |
922 | + { |
923 | + int n = 0; |
924 | + |
925 | + @Override |
926 | + public void visit(IndexName idx) |
927 | + { |
928 | + ++n; |
929 | + } |
930 | + |
931 | + @Override |
932 | + public void endOfTree() |
933 | + { |
934 | + assertEquals (0, n); |
935 | + } |
936 | + }); |
937 | + |
938 | + |
939 | + } |
940 | + |
941 | + |
942 | + private static interface Visitor |
943 | + { |
944 | + void visit(IndexName idx); |
945 | + void endOfTree(); |
946 | + } |
947 | + |
948 | + private class DropIndex implements Runnable |
949 | + { |
950 | + @Override |
951 | + public void run() |
952 | + { |
953 | + Connection conn; |
954 | + try { |
955 | + conn = DriverManager.getConnection("jdbc:default:connection", "test", ""); |
956 | + conn.createStatement().execute("DROP INDEX test.o.idx3_o"); |
957 | + } catch (SQLException e) { |
958 | + logger.error("drop index failed; {}", e.getMessage()); |
959 | + assertTrue ("Drop index failed", false); |
960 | + } |
961 | + //IndexName name = new IndexName (new TableName(SCHEMA, "o"), "idx3_o"); |
962 | + //deleteFullTextIndex(serviceManager(), name); |
963 | + } |
964 | + }; |
965 | + |
966 | + |
967 | + |
968 | + private static void traverse(FullTextIndexServiceImpl serv, |
969 | + Visitor visitor) throws PersistitException |
970 | + { |
971 | + Session session = new SessionServiceImpl().createSession(); |
972 | + |
973 | + try |
974 | + { |
975 | + Exchange ex = serv.getPopulateExchange(session); |
976 | + IndexName toPopulate; |
977 | + while ((toPopulate = serv.nextInQueue(session, ex, true)) != null) |
978 | + visitor.visit(toPopulate); |
979 | + visitor.endOfTree(); |
980 | + } |
981 | + finally |
982 | + { |
983 | + session.close(); |
984 | + } |
985 | + } |
986 | +} |
987 | |
988 | === modified file 'src/test/java/com/akiban/server/service/text/FullTextIndexServiceIT.java' |
989 | --- src/test/java/com/akiban/server/service/text/FullTextIndexServiceIT.java 2013-04-22 19:01:34 +0000 |
990 | +++ src/test/java/com/akiban/server/service/text/FullTextIndexServiceIT.java 2013-05-09 13:22:31 +0000 |
991 | @@ -38,10 +38,11 @@ |
992 | import com.persistit.exception.PersistitException; |
993 | import org.junit.Before; |
994 | import org.junit.Test; |
995 | +import org.slf4j.Logger; |
996 | +import org.slf4j.LoggerFactory; |
997 | + |
998 | import static org.junit.Assert.*; |
999 | |
1000 | -import java.util.*; |
1001 | - |
1002 | public class FullTextIndexServiceIT extends ITBase |
1003 | { |
1004 | public static final String SCHEMA = "test"; |
1005 | @@ -49,6 +50,8 @@ |
1006 | protected Schema schema; |
1007 | protected PersistitAdapter adapter; |
1008 | protected QueryContext queryContext; |
1009 | + private static final Logger logger = LoggerFactory.getLogger(FullTextIndexServiceIT.class); |
1010 | + |
1011 | |
1012 | private int c; |
1013 | private int o; |
1014 | @@ -108,6 +111,7 @@ |
1015 | assertEquals(FullTextIndexServiceImpl.class, fullText.getClass()); |
1016 | FullTextIndexServiceImpl fullTextImpl = (FullTextIndexServiceImpl)fullText; |
1017 | |
1018 | + logger.error ("DDL Service: {}", ddl().getClass().getCanonicalName()); |
1019 | // disable the populate worker (so it doesn't read all the entries |
1020 | // out before we get a chance to look at the tree. |
1021 | fullTextImpl.disablePopulateWorker(); |
1022 | @@ -246,7 +250,7 @@ |
1023 | { |
1024 | Exchange ex = serv.getPopulateExchange(session); |
1025 | IndexName toPopulate; |
1026 | - while ((toPopulate = serv.nextInQueue(ex)) != null) |
1027 | + while ((toPopulate = serv.nextInQueue(session, ex, true)) != null) |
1028 | visitor.visit(toPopulate); |
1029 | visitor.endOfTree(); |
1030 | } |
There seems to be unrelated changes related to REST and session handling. Are those ready to go or shall we revert for now?
Otherwise looks as described, still thinking through though.