Merge lp:~oontvoo/akiban-server/bug_drop_fulltext_index into lp:~akiban-technologies/akiban-server/trunk
- bug_drop_fulltext_index
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Nathan Williams |
Approved revision: | 2647 |
Merged at revision: | 2652 |
Proposed branch: | lp:~oontvoo/akiban-server/bug_drop_fulltext_index |
Merge into: | lp:~akiban-technologies/akiban-server/trunk |
Prerequisite: | lp:~oontvoo/akiban-server/new-trunk_do-maintenance |
Diff against target: |
542 lines (+122/-84) 14 files modified
src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java (+4/-2) src/main/java/com/akiban/server/service/text/FullTextIndexInfo.java (+3/-2) src/main/java/com/akiban/server/service/text/FullTextIndexInfosImpl.java (+5/-6) src/main/java/com/akiban/server/service/text/FullTextIndexService.java (+2/-1) src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java (+20/-17) src/main/java/com/akiban/server/service/text/FullTextIndexShared.java (+0/-1) src/main/java/com/akiban/server/store/PersistitStore.java (+24/-0) src/main/java/com/akiban/sql/aisddl/IndexDDL.java (+1/-1) src/test/java/com/akiban/server/service/config/TestConfigService.java (+3/-0) src/test/java/com/akiban/server/service/text/FullTextIndexServiceIT.java (+3/-42) src/test/java/com/akiban/server/test/ApiTestBase.java (+6/-0) src/test/java/com/akiban/sql/optimizer/OptimizerTestBase.java (+2/-11) src/test/java/com/akiban/sql/pg/PostgresServerMiscYamlIT.java (+4/-1) src/test/resources/com/akiban/sql/pg/yaml/functional/test-drop-fulltext.yaml (+45/-0) |
To merge this branch: | bzr merge lp:~oontvoo/akiban-server/bug_drop_fulltext_index |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Nathan Williams | Approve | ||
Vy Nguyen (community) | Needs Resubmitting | ||
Review via email: mp+159495@code.launchpad.net |
This proposal supersedes a proposal from 2013-04-15.
Commit message
Description of the change
fix drop fulltext index bug (bug 1163026) and bug1154336
[Resubmit with pre-requisite: lp:~oontvoo/akiban-server/new-trunk_do-maintenance]
[ Resubmit #2: Remove pre-req because it is in trunk]
Nathan Williams (nwilliams) wrote : Posted in a previous version of this proposal | # |
Vy Nguyen (oontvoo) wrote : Posted in a previous version of this proposal | # |
PersisitStore.java - line 1554 (+/- a few lines)
It looks like the index needs to be 'attached' to an IndexDef.
Nathan Williams (nwilliams) wrote : Posted in a previous version of this proposal | # |
Only to delete the tree, which full texts don't have.
DDLFunctions has separate methods for dropping table and group indexes. Something different needs to happen for full texts (i.e. FullTextIndexSe
Nathan Williams (nwilliams) wrote : Posted in a previous version of this proposal | # |
Actually, handling the distinction in PS#deleteIndexes() would let dropTableInternal() use it as well, so I'm fine with that too.
Vy Nguyen (oontvoo) wrote : Posted in a previous version of this proposal | # |
skip fulltext index in persistitStore.
Nathan Williams (nwilliams) wrote : Posted in a previous version of this proposal | # |
Since we're here, can you please fix the other bug I mentioned. We just need to call FTIS#dropIndex() for them.
Vy Nguyen (oontvoo) wrote : Posted in a previous version of this proposal | # |
I am having a compilation-error in
src/test/
(I declared FTS as an argument in PersistStore's ctor, and other places where it's called.)
What did I miss?
Vy Nguyen (oontvoo) wrote : Posted in a previous version of this proposal | # |
Hm, never mind, found it!
Nathan Williams (nwilliams) wrote : Posted in a previous version of this proposal | # |
Look at FailureOnStartu
Vy Nguyen (oontvoo) wrote : Posted in a previous version of this proposal | # |
Actually, it's more complicated than just calling FTS.dropIndex()
+ By the time deleteIndexes() is called, the index is no longer in AIS for FullTextIndexSh
+ In order for dropIndex() to work, the index needs to be in 'indexes' map, which none of the current fulltext index is because no one puts it in there. The createIndex() method, which would do this, needs to be called manually.
This problem is solved in the do-maintenance branch. And I can certainly have it fix the bug you mentioned. (In fact, I tried merging this branch into it and the delete works correctly, which it wouldn't in this branch).
Nathan Williams (nwilliams) wrote : Posted in a previous version of this proposal | # |
> By the time deleteIndexes() is called, the index is no
> longer in AIS for FullTextIndexSh
It does not need to be in the current AIS and probably shouldn't be, given that it's being removed. Look at the flow of the other drop methods (e.g. table, index). The AIS changes are performed through the SchemaManager before tree deletion is done. You can either hang onto the 'old' AIS or get it through the Index reference.
> In order for dropIndex() to work, the index needs to be in 'indexes' map,
It should be, and sounds like will be once your other branch is in, but doesn't need to be. The getIndex() method will populate the indexes map on demand. It creates a value cached on the AIS, which is going away in this case, but will work just fine.
Vy Nguyen (oontvoo) wrote : Posted in a previous version of this proposal | # |
clean up and more tests
Nathan Williams (nwilliams) wrote : | # |
akserver.
The new getIndexToDrop() helper is misleading. It will throw NoSuchIndex if the cache hasn't been created (e.g. create a FT and then immediately drop). Using the existing method is fine. Attempting to optimize away the Info creation is just noise.
Otherwise looks good.
Vy Nguyen (oontvoo) wrote : | # |
A few *subtle* changes:
- in removeTrees():
The change is to ensure dropIndex is called on a particular index only once (for the same reason described in the comment in the code)
- in FullTextIndexSe
Because fullText index deletions were not done properly (which is what the branch is trying to fix), these test methods could call FTS.dropIndex() whenever they want.
Now that the bug is fixed, these should not eagerly drop the index (simply to remove it from the tree( because tearDown() would then not be able to find the indices to really drop them.
- About your comment on getIndexToDrop()
The error message could change, but using the existing method would require some mechanism to ensure the downstream methods lookup the index in the old AIS, not the new one, because the index is no longer in there. And all that is just not necessary because all we really want to do here is to remove the index from the cache and delete relating document(s).
Deleting the index right after creating it is similar to using it right after creation. Unexpected things could happen, given that the index is populated asynchronously .
Vy Nguyen (oontvoo) : | # |
Nathan Williams (nwilliams) wrote : | # |
There is a helper to return the 'owned' full text indexes: UserTable#
Multiple tests still set the indexpath and working intervals.
The re-insertion in FullTextIndexSe
We can't rely on the contents of the cache to determine whether or not there is work to do. It is a cache and can be empty at any time. The decision *must* be made on the basis of the presence in the AIS. Getting it from the old AIS is simple, just pass it the old AIS.
We also can't say that "unexpected things could happen" if you drop an index. Not a very good user experience. Instead, we should ensure that the correct thing always happens. I see that the existing dropIndex() attempts to remove a 'promise' for population. That isn't enough, given that they could be concurrent. Instead, a shared claim should be made during the population or maintenance steps (see LockService). An exclusive claim is already taken during DROP processing.
Vy Nguyen (oontvoo) wrote : | # |
> The re-insertion in FullTextIndexSe
> needs rewritten or tearDown's assumptions need changed, though I didn't see
> what tearDown was actually refering too.
>
tearDown() is called automatically at the end of the test class to drop all tables/
The test is intended to test the the populate-worker, NOT the deletion of the index per se.
In other words, we wanted to make sure that when a fulltext index is created, an entry about it is inserted into a tree for later processing, but if the index is dropped before the time scheduled for population, we wants to make sure the entry is removed from that tree. Otherwise, when the worker wakes up, it will populate a non-existing index.
> We can't rely on the contents of the cache to determine whether or not there
> is work to do. It is a cache and can be empty at any time. The decision *must*
> be made on the basis of the presence in the AIS. Getting it from the old AIS
> is simple, just pass it the old AIS.
I believe I misused the word 'cache' in the resubmit comment. What I really meant was FTS.dropIndex() only needed to remove the entry about the index from the hashmap (ie., `indexes`), and to delete relating document(s).
It wasn't checking some cache to see if the given index exists in there. The index must exist in `indexes` if it was properly populated.
Now that I thought about it, throwing an error on line 44 is 'over-reacting'. That wouldn't really be an error. Probably just a warning in the debug log would be sufficient. The only time this would happen is, as you said, when the index is deleted before it was populated, and because all that FTS.dropIndex() is responsible for doing is to clean up the stuff that only exists *after* the population, there is nothing to do here (other than removing the 'promise' for population, of course).
Nathan Williams (nwilliams) wrote : | # |
> The test is intended to test the the populate-worker, NOT
> the deletion of the index per se. In other words, we wanted
> to make sure that when a fulltext index is created, an entry
> about it is inserted into a tree for later processing, but if
> the index is dropped before the time scheduled for population,
> we wants to make sure the entry is removed from that tree
Since, I believe, we should claim a lock on the table when performing the populate or update, this would be a good time to check that the index still exists. If it doesn't, the entry from the background tree can be removed and all work skipped. As I mentioned in the previous comment, removing the entry from the dropIndex() processing isn't enough.
> I believe I misused the word 'cache' in the resubmit comment.
Cache is the correct word. The IndexInfo is stored in a cache that is attached to the AIS. We can make no assumptions about its contents or lifetime.
> The only time this would happen is, as you said, when the index is
> deleted before it was populated,
No. The best way to think of it is really as a cache that can be cleared at any time. In the current implementation, the cache will be empty any time there is *any* DDL, not just one related to the table. This is because a brand new AIS each time.time.
Vy Nguyen (oontvoo) wrote : | # |
- construct a simple* FulLTextIndexSh
This should get rid of the NoSuchIndexExce
*simple* because we don't want to
(1) cache the object in AIS (No one is ever going to use the cached value)
(2) compute operator plan for lookup the rows of the index (same reason as above)
(3) All that we wants here is the path to the document file(s)
Nathan Williams (nwilliams) wrote : | # |
As I mentioned a number of comments ago, optimizing away the cache generation is noise. The unlikely case is it doesn't exist. Less code is generally better.
Please address the issues in my previous comments most importantly locking but also duplicate settings tests.
Vy Nguyen (oontvoo) wrote : | # |
> As I mentioned a number of comments ago, optimizing away the cache generation
> is noise.
> The unlikely case is it doesn't exist.
That is not a *little* optimisation. The current getIndex() would cause a bunch of stuff to be done including building a list of rowTypes and computing plans to lookup related rows. Why would we want to do all that just to delete the index?
> Please address the issues in my previous comments most importantly locking but
> also duplicate settings tests.
I did. All the settings are gone, only TestConfigService still sets the interval now.
What about locking that you were getting at? If that's about an entry being the tree possibly being modified elsewhere, too, it's addressed in the ww_bug branch that I just put in.
Nathan Williams (nwilliams) wrote : | # |
> That is not a *little* optimisation. The current getIndex()
> would cause a bunch of stuff to be done including building
> a list of rowTypes and computing plans to lookup related
> rows. Why would we want to do all that just to delete the
> index?
The amount of time that the getIndex() would take compared to the rest of the DROP processing is miniscule. Yes, it creates a little garbage but that's about it.
Why? As I said earlier, less code is generally better. Less to understand, maintain, document, and test. In a scenario where we can have a single code path vs two, and the cost is a little garbage in uncommon scenarios, I'll always choose the former.
> I did. All the settings are gone, only TestConfigService still
> sets the interval now.
OptimizerTestBa
OptimizerTestBa
OptimizerTestBa
TestConfigService also declares TEXT_INDEX_
> What about locking that you were getting at?
As I mentioned previously, removing the key in FTSISI#
Vy Nguyen (oontvoo) wrote : | # |
- configs: removed
- locking: this is addressed the ww_bug. I am not going to touch it here.
- I still don't see your arguments about more vs less code. To use the current code (ie., getIndex), we'd need to pass the old AIS to it, which'd lead to a series of change in its callers to take the AIS all the way from [Index|Table| *]DDL.java.
That doesn't look any less code.
At least, the current change is local.
Nathan Williams (nwilliams) wrote : | # |
Thanks for the tweaks.
> - locking: this is addressed the ww_bug. I am not going to
> touch it here.
The other branch addresses part, but not all unfortunately. Note the specific cases I said in the previous comment (i.e. writes before populate is done). Doing this in another branch is fine.
> - I still don't see your arguments about more vs less code.
> To use the current code (ie., getIndex), we'd need to pass the
> old AIS to it,
In this instance, it's already immediately available: idx.getIndexedT
Vy Nguyen (oontvoo) wrote : | # |
use the old AIS when neccessary
Preview Diff
1 | === modified file 'src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java' |
2 | --- src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-04-14 04:32:58 +0000 |
3 | +++ src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-04-29 16:13:27 +0000 |
4 | @@ -1032,8 +1032,10 @@ |
5 | Collection<Index> indexes = new HashSet<>(); |
6 | for(String indexName : indexNamesToDrop) { |
7 | Index index = table.getIndex(indexName); |
8 | - if(index == null) { |
9 | - throw new NoSuchIndexException (indexName); |
10 | + if(index == null |
11 | + && !(table.isUserTable() |
12 | + && ((index = ((UserTable)table).getFullTextIndex(indexName)) != null))) { |
13 | + throw new NoSuchIndexException (indexName); |
14 | } |
15 | if(index.isPrimaryKey()) { |
16 | throw new ProtectedIndexException(indexName, table.getName()); |
17 | |
18 | === modified file 'src/main/java/com/akiban/server/service/text/FullTextIndexInfo.java' |
19 | --- src/main/java/com/akiban/server/service/text/FullTextIndexInfo.java 2013-04-01 19:04:26 +0000 |
20 | +++ src/main/java/com/akiban/server/service/text/FullTextIndexInfo.java 2013-04-29 16:13:27 +0000 |
21 | @@ -264,10 +264,11 @@ |
22 | return indexer; |
23 | } |
24 | |
25 | - // TODO: _Lookup plan to get rows just from a row being updated. |
26 | - |
27 | public void deletePath() { |
28 | File path = shared.getPath(); |
29 | + // no doc to delete |
30 | + if (!path.exists() || path.listFiles() == null) |
31 | + return; |
32 | for (File f : path.listFiles()) { |
33 | f.delete(); |
34 | } |
35 | |
36 | === modified file 'src/main/java/com/akiban/server/service/text/FullTextIndexInfosImpl.java' |
37 | --- src/main/java/com/akiban/server/service/text/FullTextIndexInfosImpl.java 2013-03-22 20:05:57 +0000 |
38 | +++ src/main/java/com/akiban/server/service/text/FullTextIndexInfosImpl.java 2013-04-29 16:13:27 +0000 |
39 | @@ -21,7 +21,6 @@ |
40 | import com.akiban.ais.model.IndexName; |
41 | import com.akiban.qp.operator.QueryContext; |
42 | import com.akiban.qp.rowtype.RowType; |
43 | -import com.akiban.qp.rowtype.Schema; |
44 | import com.akiban.server.error.FullTextQueryParseException; |
45 | import com.akiban.server.service.session.Session; |
46 | |
47 | @@ -30,7 +29,6 @@ |
48 | import org.apache.lucene.search.Query; |
49 | |
50 | import java.io.File; |
51 | -import java.io.IOException; |
52 | import java.util.HashMap; |
53 | import java.util.Map; |
54 | |
55 | @@ -41,7 +39,7 @@ |
56 | @Override |
57 | public Query parseQuery(QueryContext context, IndexName name, |
58 | String defaultField, String query) { |
59 | - FullTextIndexInfo index = getIndex(context.getSession(), name); |
60 | + FullTextIndexInfo index = getIndex(context.getSession(), name, null); |
61 | if (defaultField == null) { |
62 | defaultField = index.getDefaultFieldName(); |
63 | } |
64 | @@ -58,15 +56,16 @@ |
65 | |
66 | @Override |
67 | public RowType searchRowType(Session session, IndexName name) { |
68 | - FullTextIndexInfo index = getIndex(session, name); |
69 | + FullTextIndexInfo index = getIndex(session, name, null); |
70 | return index.getHKeyRowType(); |
71 | } |
72 | |
73 | protected abstract AkibanInformationSchema getAIS(Session session); |
74 | protected abstract File getIndexPath(); |
75 | |
76 | - protected FullTextIndexInfo getIndex(Session session, IndexName name) { |
77 | - AkibanInformationSchema ais = getAIS(session); |
78 | + protected FullTextIndexInfo getIndex(Session session, IndexName name, AkibanInformationSchema ais) { |
79 | + if (ais == null) |
80 | + ais = getAIS(session); |
81 | FullTextIndexInfo info; |
82 | synchronized (indexes) { |
83 | FullTextIndexShared shared = indexes.get(name); |
84 | |
85 | === modified file 'src/main/java/com/akiban/server/service/text/FullTextIndexService.java' |
86 | --- src/main/java/com/akiban/server/service/text/FullTextIndexService.java 2013-04-08 19:43:08 +0000 |
87 | +++ src/main/java/com/akiban/server/service/text/FullTextIndexService.java 2013-04-29 16:13:27 +0000 |
88 | @@ -17,6 +17,7 @@ |
89 | |
90 | package com.akiban.server.service.text; |
91 | |
92 | +import com.akiban.ais.model.FullTextIndex; |
93 | import com.akiban.ais.model.IndexName; |
94 | import com.akiban.qp.operator.Cursor; |
95 | import com.akiban.qp.operator.QueryContext; |
96 | @@ -50,7 +51,7 @@ |
97 | * @return An array of available background works |
98 | */ |
99 | public List<? extends BackgroundWork> getBackgroundWorks(); |
100 | - public void dropIndex(Session session, IndexName name); |
101 | + public void dropIndex(Session session, FullTextIndex name); |
102 | public Cursor searchIndex(QueryContext context, IndexName name, |
103 | Query query, int limit); |
104 | } |
105 | |
106 | === modified file 'src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java' |
107 | --- src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java 2013-04-17 17:51:15 +0000 |
108 | +++ src/main/java/com/akiban/server/service/text/FullTextIndexServiceImpl.java 2013-04-29 16:13:27 +0000 |
109 | @@ -18,7 +18,7 @@ |
110 | package com.akiban.server.service.text; |
111 | |
112 | import com.akiban.ais.model.AkibanInformationSchema; |
113 | -import com.akiban.ais.model.Index; |
114 | +import com.akiban.ais.model.FullTextIndex; |
115 | import com.akiban.ais.model.IndexName; |
116 | import com.akiban.ais.model.TableName; |
117 | import com.akiban.ais.model.UserTable; |
118 | @@ -34,7 +34,6 @@ |
119 | import com.akiban.qp.rowtype.HKeyRowType; |
120 | import com.akiban.qp.util.HKeyCache; |
121 | import com.akiban.server.error.AkibanInternalException; |
122 | -import com.akiban.server.service.BackgroundObserver; |
123 | import com.akiban.server.service.BackgroundWork; |
124 | import com.akiban.server.service.BackgroundWorkBase; |
125 | import com.akiban.server.service.Service; |
126 | @@ -63,8 +62,6 @@ |
127 | import java.util.Arrays; |
128 | import java.util.Collections; |
129 | import java.util.List; |
130 | -import java.util.Observable; |
131 | -import java.util.Observer; |
132 | import java.util.Timer; |
133 | import java.util.TimerTask; |
134 | |
135 | @@ -114,7 +111,7 @@ |
136 | /* FullTextIndexService */ |
137 | |
138 | private long createIndex(Session session, IndexName name) { |
139 | - FullTextIndexInfo index = getIndex(session, name); |
140 | + FullTextIndexInfo index = getIndex(session, name, null); |
141 | try { |
142 | return populateIndex(session, index); |
143 | } |
144 | @@ -123,12 +120,10 @@ |
145 | } |
146 | } |
147 | |
148 | - @Override |
149 | - public void dropIndex(Session session, IndexName name) { |
150 | - |
151 | + void deleteFromTree(Session session, IndexName name) |
152 | + { |
153 | try |
154 | { |
155 | - // see if there exists a promise for populating this index |
156 | Exchange ex = getPopulateExchange(session); |
157 | ex.clear().append(name.getSchemaName()) |
158 | .append(name.getTableName()) |
159 | @@ -136,22 +131,29 @@ |
160 | |
161 | if (ex.traverse(Key.Direction.EQ, true, 0)) |
162 | ex.fetchAndRemove(); |
163 | - |
164 | - FullTextIndexInfo index = getIndex(session, name); |
165 | - index.deletePath(); |
166 | - synchronized (indexes) { |
167 | - indexes.remove(name); |
168 | - } |
169 | } |
170 | catch (PersistitException e) |
171 | { |
172 | throw new AkibanInternalException("Error while removing index", e); |
173 | } |
174 | } |
175 | + |
176 | + @Override |
177 | + public void dropIndex(Session session, FullTextIndex idx) { |
178 | + // delete 'promise' for population, if any |
179 | + deleteFromTree(session, idx.getIndexName()); |
180 | + |
181 | + // delete documents |
182 | + FullTextIndexInfo idxInfo = getIndex(session, idx.getIndexName(), idx.getIndexedTable().getAIS()); |
183 | + idxInfo.deletePath(); |
184 | + synchronized (indexes) { |
185 | + indexes.remove(idx.getIndexName()); |
186 | + } |
187 | + } |
188 | |
189 | @Override |
190 | public Cursor searchIndex(QueryContext context, IndexName name, Query query, int limit) { |
191 | - FullTextIndexInfo index = getIndex(context.getSession(), name); |
192 | + FullTextIndexInfo index = getIndex(context.getSession(), name, null); |
193 | try { |
194 | return index.getSearcher().search(context, index.getHKeyRowType(), |
195 | query, limit); |
196 | @@ -172,6 +174,7 @@ |
197 | @Override |
198 | public void start() { |
199 | persistitStore = store.getPersistitStore(); |
200 | + persistitStore.setFullTextService(this); |
201 | enableUpdateWorker(); |
202 | enablePopulateWorker(); |
203 | } |
204 | @@ -255,7 +258,7 @@ |
205 | { |
206 | try |
207 | { |
208 | - FullTextIndexInfo indexInfo = getIndex(session, name); |
209 | + FullTextIndexInfo indexInfo = getIndex(session, name, null); |
210 | StoreAdapter adapter = session.get(StoreAdapter.STORE_ADAPTER_KEY); |
211 | if (adapter == null) |
212 | adapter = new PersistitAdapter(indexInfo.getSchema(), |
213 | |
214 | === modified file 'src/main/java/com/akiban/server/service/text/FullTextIndexShared.java' |
215 | --- src/main/java/com/akiban/server/service/text/FullTextIndexShared.java 2013-03-22 20:05:57 +0000 |
216 | +++ src/main/java/com/akiban/server/service/text/FullTextIndexShared.java 2013-04-29 16:13:27 +0000 |
217 | @@ -27,7 +27,6 @@ |
218 | import org.apache.lucene.store.FSDirectory; |
219 | |
220 | import java.io.*; |
221 | -import java.util.List; |
222 | import java.util.Set; |
223 | |
224 | public class FullTextIndexShared implements CacheValueGenerator<FullTextIndexInfo>, Closeable |
225 | |
226 | === modified file 'src/main/java/com/akiban/server/store/PersistitStore.java' |
227 | --- src/main/java/com/akiban/server/store/PersistitStore.java 2013-04-15 16:20:25 +0000 |
228 | +++ src/main/java/com/akiban/server/store/PersistitStore.java 2013-04-29 16:13:27 +0000 |
229 | @@ -18,6 +18,7 @@ |
230 | package com.akiban.server.store; |
231 | |
232 | import com.akiban.ais.model.*; |
233 | +import com.akiban.ais.model.Index.IndexType; |
234 | import com.akiban.qp.operator.StoreAdapter; |
235 | import com.akiban.qp.persistitadapter.OperatorBasedRowCollector; |
236 | import com.akiban.qp.persistitadapter.PersistitAdapter; |
237 | @@ -41,6 +42,7 @@ |
238 | import com.akiban.server.service.config.ConfigurationService; |
239 | import com.akiban.server.service.lock.LockService; |
240 | import com.akiban.server.service.session.Session; |
241 | +import com.akiban.server.service.text.FullTextIndexService; |
242 | import com.akiban.server.service.transaction.TransactionService; |
243 | import com.akiban.server.service.tree.TreeLink; |
244 | import com.akiban.server.service.tree.TreeService; |
245 | @@ -130,6 +132,8 @@ |
246 | |
247 | private int deferredIndexKeyLimit = MAX_INDEX_TRANCHE_SIZE; |
248 | |
249 | + private FullTextIndexService fullTextService; |
250 | + |
251 | private RowDataValueCoder valueCoder; |
252 | |
253 | // Each row change has a 'uniqueChangeId', stored in the 'maintenance.full_text' table |
254 | @@ -157,6 +161,11 @@ |
255 | this.transactionService = transactionService; |
256 | } |
257 | |
258 | + public void setFullTextService(FullTextIndexService service) |
259 | + { |
260 | + fullTextService = service; |
261 | + } |
262 | + |
263 | // --- for tracking changes |
264 | private Exchange getChangeExchange(Session session) throws PersistitException |
265 | { |
266 | @@ -1890,6 +1899,14 @@ |
267 | @Override |
268 | public void removeTrees(Session session, Table table) { |
269 | Collection<TreeLink> treeLinks = new ArrayList<>(); |
270 | + |
271 | + // delete all fulltext indexes |
272 | + if (table.isUserTable()) |
273 | + { |
274 | + for (FullTextIndex idx : ((UserTable)table).getOwnFullTextIndexes()) |
275 | + fullTextService.dropIndex(session, idx); |
276 | + } |
277 | + |
278 | // Add all index trees |
279 | final Collection<TableIndex> tableIndexes = table.isUserTable() ? ((UserTable)table).getIndexesIncludingInternal() : table.getIndexes(); |
280 | final Collection<GroupIndex> groupIndexes = table.getGroupIndexes(); |
281 | @@ -1931,6 +1948,13 @@ |
282 | public void deleteIndexes(final Session session, final Collection<? extends Index> indexes) { |
283 | List<TreeLink> links = new ArrayList<>(indexes.size()); |
284 | for(Index index : indexes) { |
285 | + // no trees to drop |
286 | + if (index.getIndexType() == IndexType.FULL_TEXT) |
287 | + { |
288 | + fullTextService.dropIndex(session, (FullTextIndex)index); |
289 | + indexes.remove(index); |
290 | + continue; |
291 | + } |
292 | final IndexDef indexDef = index.indexDef(); |
293 | if(indexDef == null) { |
294 | throw new IllegalStateException("indexDef is null for index: " + index); |
295 | |
296 | === modified file 'src/main/java/com/akiban/sql/aisddl/IndexDDL.java' |
297 | --- src/main/java/com/akiban/sql/aisddl/IndexDDL.java 2013-03-27 04:42:10 +0000 |
298 | +++ src/main/java/com/akiban/sql/aisddl/IndexDDL.java 2013-04-29 16:13:27 +0000 |
299 | @@ -89,7 +89,7 @@ |
300 | } |
301 | // if we can't find the index, set tableName to null |
302 | // to flag not a user table index. |
303 | - if (table.getIndex(indexName) == null) { |
304 | + if (table.getIndex(indexName) == null && table.getFullTextIndex(indexName) == null) { |
305 | tableName = null; |
306 | } |
307 | // Check the group associated to the table for the |
308 | |
309 | === modified file 'src/test/java/com/akiban/server/service/config/TestConfigService.java' |
310 | --- src/test/java/com/akiban/server/service/config/TestConfigService.java 2013-03-22 20:05:57 +0000 |
311 | +++ src/test/java/com/akiban/server/service/config/TestConfigService.java 2013-04-29 16:13:27 +0000 |
312 | @@ -22,6 +22,7 @@ |
313 | import com.akiban.server.service.plugins.Plugin; |
314 | import com.akiban.server.service.plugins.PluginsFinder; |
315 | |
316 | +import com.akiban.server.service.text.FullTextIndexServiceImpl; |
317 | import java.io.File; |
318 | import java.util.Collection; |
319 | import java.util.Collections; |
320 | @@ -60,6 +61,8 @@ |
321 | protected Map<String, String> loadProperties() { |
322 | Map<String, String> ret = new HashMap<>(super.loadProperties()); |
323 | makeDataDirectory(); |
324 | + ret.put(FullTextIndexServiceImpl.UPDATE_INTERVAL, Long.toString(1000)); |
325 | + ret.put(FullTextIndexServiceImpl.POPULATE_DELAY_INTERVAL, Long.toString(1000)); |
326 | ret.put(DATA_PATH_KEY, dataDirectory.getAbsolutePath()); |
327 | ret.put(TEXT_INDEX_PATH_KEY, dataDirectory.getAbsolutePath()); |
328 | final int bufferSize = Integer.parseInt(ret.get(BUFFER_SIZE_KEY)); |
329 | |
330 | === modified file 'src/test/java/com/akiban/server/service/text/FullTextIndexServiceIT.java' |
331 | --- src/test/java/com/akiban/server/service/text/FullTextIndexServiceIT.java 2013-04-15 19:21:09 +0000 |
332 | +++ src/test/java/com/akiban/server/service/text/FullTextIndexServiceIT.java 2013-04-29 16:13:27 +0000 |
333 | @@ -45,8 +45,6 @@ |
334 | public class FullTextIndexServiceIT extends ITBase |
335 | { |
336 | public static final String SCHEMA = "test"; |
337 | - private static final long updateInterval = 1000L; // for testing |
338 | - private static final long populateDelayInterval = 1000L; |
339 | protected FullTextIndexService fullText; |
340 | protected Schema schema; |
341 | protected PersistitAdapter adapter; |
342 | @@ -63,15 +61,6 @@ |
343 | .bindAndRequire(FullTextIndexService.class, FullTextIndexServiceImpl.class); |
344 | } |
345 | |
346 | - @Override |
347 | - protected Map<String, String> startupConfigProperties() { |
348 | - Map<String, String> properties = new HashMap<>(); |
349 | - properties.put("akserver.text.indexpath", "/tmp/aktext"); |
350 | - properties.put(FullTextIndexServiceImpl.UPDATE_INTERVAL, Long.toString(updateInterval)); |
351 | - properties.put(FullTextIndexServiceImpl.POPULATE_DELAY_INTERVAL, Long.toString(populateDelayInterval)); |
352 | - return properties; |
353 | - } |
354 | - |
355 | @Before |
356 | public void createData() { |
357 | c = createTable(SCHEMA, "c", |
358 | @@ -179,12 +168,6 @@ |
359 | assertEquals (0, n); |
360 | } |
361 | }); |
362 | - |
363 | - // drop all the indices |
364 | - Session session = new SessionServiceImpl().createSession(); |
365 | - for (FullTextIndex idx : expecteds) |
366 | - fullTextImpl.dropIndex(session, idx.getIndexName()); |
367 | - session.close(); |
368 | } |
369 | |
370 | |
371 | @@ -217,29 +200,9 @@ |
372 | |
373 | // <3> delete 2 of them |
374 | Session session = new SessionServiceImpl().createSession(); |
375 | - boolean sawNPE = false; |
376 | - try |
377 | - { |
378 | - fullTextImpl.dropIndex(session, expecteds[0].getIndexName()); |
379 | - } |
380 | - catch (NullPointerException e) // NPE is expected because, the index hasn't been |
381 | - { // populated yet. But we're not testing that! |
382 | - sawNPE = true; |
383 | - } |
384 | - assertTrue("NPE should have happened", sawNPE); |
385 | - |
386 | + deleteFullTextIndex(serviceManager(), expecteds[0].getIndexName()); |
387 | + deleteFullTextIndex(serviceManager(), expecteds[1].getIndexName()); |
388 | |
389 | - sawNPE = false; |
390 | - try |
391 | - { |
392 | - fullTextImpl.dropIndex(session, expecteds[1].getIndexName()); |
393 | - } |
394 | - catch (NullPointerException e) // NPE is expected because, the index hasn't been |
395 | - { // populated yet. But we're not testing that! |
396 | - sawNPE = true; |
397 | - } |
398 | - assertTrue("NPE should have happened", sawNPE); |
399 | - |
400 | // <4> check that the tree only has one entry now (ie., epxecteds2[2] |
401 | traverse(fullTextImpl, |
402 | new Visitor() |
403 | @@ -259,13 +222,11 @@ |
404 | assertEquals (1, n); |
405 | } |
406 | }); |
407 | - |
408 | + |
409 | // wake the worker up to do its job |
410 | fullTextImpl.enablePopulateWorker(); |
411 | WaitFunctionHelpers.waitOn(fullText.getBackgroundWorks()); |
412 | |
413 | - // drop the remaining index |
414 | - fullTextImpl.dropIndex(session, expecteds[2].getIndexName()); |
415 | session.close(); |
416 | } |
417 | |
418 | |
419 | === modified file 'src/test/java/com/akiban/server/test/ApiTestBase.java' |
420 | --- src/test/java/com/akiban/server/test/ApiTestBase.java 2013-04-10 18:32:00 +0000 |
421 | +++ src/test/java/com/akiban/server/test/ApiTestBase.java 2013-04-29 16:13:27 +0000 |
422 | @@ -767,6 +767,12 @@ |
423 | return ddl().getAIS(session()).getGroup(groupName).getIndex(indexName); |
424 | } |
425 | |
426 | + protected final void deleteFullTextIndex(ServiceManager sm, IndexName name) |
427 | + { |
428 | + ddl().dropTableIndexes(session(), name.getFullTableName(), Arrays.asList(name.getName())); |
429 | + updateAISGeneration(); |
430 | + } |
431 | + |
432 | protected final FullTextIndex createFullTextIndex(ServiceManager sm, String schema, String table, String indexName, String... indexCols) { |
433 | AkibanInformationSchema tempAIS = createIndexInternal(schema, table, indexName, "FULL_TEXT(" + Strings.join(Arrays.asList(indexCols), ",") + ")"); |
434 | Index tempIndex = tempAIS.getUserTable(schema, table).getFullTextIndex(indexName); |
435 | |
436 | === modified file 'src/test/java/com/akiban/sql/optimizer/OptimizerTestBase.java' |
437 | --- src/test/java/com/akiban/sql/optimizer/OptimizerTestBase.java 2013-04-01 19:04:26 +0000 |
438 | +++ src/test/java/com/akiban/sql/optimizer/OptimizerTestBase.java 2013-04-29 16:13:27 +0000 |
439 | @@ -117,7 +117,7 @@ |
440 | } |
441 | |
442 | |
443 | - protected static ServiceManager createServiceManager(Map<String, String> startupConfigProperties) |
444 | + protected static ServiceManager createServiceManager() |
445 | { |
446 | return new GuicedServiceManager(serviceBindingsProvider()); |
447 | } |
448 | @@ -130,19 +130,10 @@ |
449 | FullTextIndexServiceImpl.class); |
450 | } |
451 | |
452 | - |
453 | - protected static Map<String, String> startupConfigProperties() { |
454 | - Map<String, String> properties = new HashMap<>(); |
455 | - properties.put("akserver.text.indexpath", "/tmp/aktext"); |
456 | - properties.put(FullTextIndexServiceImpl.UPDATE_INTERVAL, Long.toString(updateInterval)); |
457 | - properties.put(FullTextIndexServiceImpl.POPULATE_DELAY_INTERVAL, Long.toString(populateDelayInterval)); |
458 | - return properties; |
459 | - } |
460 | - |
461 | private static ServiceManager prepareServices() |
462 | { |
463 | System.setProperty("akiban.home", System.getProperty("user.home")); |
464 | - ServiceManager ret = createServiceManager(startupConfigProperties()); |
465 | + ServiceManager ret = createServiceManager(); |
466 | ret.startServices(); |
467 | |
468 | return ret; |
469 | |
470 | === modified file 'src/test/java/com/akiban/sql/pg/PostgresServerMiscYamlIT.java' |
471 | --- src/test/java/com/akiban/sql/pg/PostgresServerMiscYamlIT.java 2013-04-11 05:18:38 +0000 |
472 | +++ src/test/java/com/akiban/sql/pg/PostgresServerMiscYamlIT.java 2013-04-29 16:13:27 +0000 |
473 | @@ -23,6 +23,8 @@ |
474 | import com.akiban.server.service.is.BasicInfoSchemaTablesService; |
475 | import com.akiban.server.service.is.BasicInfoSchemaTablesServiceImpl; |
476 | import com.akiban.server.service.servicemanager.GuicedServiceManager; |
477 | +import com.akiban.server.service.text.FullTextIndexService; |
478 | +import com.akiban.server.service.text.FullTextIndexServiceImpl; |
479 | import com.akiban.sql.NamedParamsTestBase; |
480 | import com.akiban.sql.embedded.EmbeddedJDBCService; |
481 | import com.akiban.sql.embedded.EmbeddedJDBCServiceImpl; |
482 | @@ -79,7 +81,8 @@ |
483 | protected GuicedServiceManager.BindingsConfigurationProvider serviceBindingsProvider() { |
484 | return super.serviceBindingsProvider() |
485 | .bindAndRequire(BasicInfoSchemaTablesService.class, BasicInfoSchemaTablesServiceImpl.class) |
486 | - .bindAndRequire(EmbeddedJDBCService.class, EmbeddedJDBCServiceImpl.class); |
487 | + .bindAndRequire(EmbeddedJDBCService.class, EmbeddedJDBCServiceImpl.class) |
488 | + .bindAndRequire(FullTextIndexService.class, FullTextIndexServiceImpl.class); |
489 | } |
490 | |
491 | @Override |
492 | |
493 | === added file 'src/test/resources/com/akiban/sql/pg/yaml/functional/test-drop-fulltext.yaml' |
494 | --- src/test/resources/com/akiban/sql/pg/yaml/functional/test-drop-fulltext.yaml 1970-01-01 00:00:00 +0000 |
495 | +++ src/test/resources/com/akiban/sql/pg/yaml/functional/test-drop-fulltext.yaml 2013-04-29 16:13:27 +0000 |
496 | @@ -0,0 +1,45 @@ |
497 | +# test drop full_text index |
498 | +--- |
499 | +- CreateTable: t(id int, name varchar(224)); |
500 | +--- |
501 | +- Statement: CREATE INDEX idx on t(full_text(name)); |
502 | +--- |
503 | +- Statement: SELECT fulltext_maintenance_wait(); |
504 | +--- |
505 | +- Statement: INSERT INTO t values (1, 'bar1'), (2, 'bar2'), (3, 'bar3'), (4, 'bar1'); |
506 | +--- |
507 | +- Statement: SELECT fulltext_maintenance_wait(); |
508 | +--- |
509 | +- Statement: SELECT id from t where full_text_search(name='bar1'); |
510 | +- output: [[1], [4]] |
511 | +--- |
512 | +- Statement: DROP INDEX t.idx; |
513 | +--- |
514 | +- DropTable: t; |
515 | +--- |
516 | +- CreateTable: t2(id int, name varchar(32)); |
517 | +--- |
518 | +- Statement: INSERT INTO t2 VALUES (1, 'John'), (2, 'Sally'); |
519 | +--- |
520 | +- Statement: CREATE INDEX t2_idx on t2(full_text(name)); |
521 | +--- |
522 | +- Statement: SELECT fulltext_maintenance_wait(); |
523 | +--- |
524 | +- Statement: SELECT * FROM t2 WHERE FULL_TEXT_SEARCH(name, 'Jo*'); |
525 | +- row_count: 0 |
526 | +--- |
527 | +- DropTable: t2; |
528 | +--- |
529 | +- CreateTable: t2(id INT NOT NULL PRIMARY KEY, name VARCHAR(32) COLLATE en_ci); |
530 | +--- |
531 | +- Statement: INSERT INTO t2 VALUES (1, 'John'), (2, 'Sally'); |
532 | +--- |
533 | +- Statement: CREATE INDEX t2_idx on t2(full_text(name)); |
534 | +--- |
535 | +- Statement: SELECT fulltext_maintenance_wait() |
536 | +--- |
537 | +- Statement: SELECT * FROM t2 WHERE FULL_TEXT_SEARCH(name, 'Jo*'); |
538 | +- output: [[1, 'John']] |
539 | +--- |
540 | +- DropTable: t2; |
541 | +... |
542 | \ No newline at end of file |
What is the IndexDef needed for?
I'm guessing bug1154336 is quite similar too. Perhaps dropTableInternal() needs to be in on the game.