Merge lp:~nwilliams/akiban-server/abstract-store into lp:~akiban-technologies/akiban-server/trunk

Proposed by Nathan Williams
Status: Merged
Merged at revision: 2659
Proposed branch: lp:~nwilliams/akiban-server/abstract-store
Merge into: lp:~akiban-technologies/akiban-server/trunk
Diff against target: 2631 lines (+822/-847)
24 files modified
src/main/java/com/akiban/ais/model/UserTable.java (+4/-0)
src/main/java/com/akiban/qp/persistitadapter/OneTableRowCollector.java (+4/-6)
src/main/java/com/akiban/qp/persistitadapter/OperatorBasedRowCollector.java (+13/-14)
src/main/java/com/akiban/qp/persistitadapter/OperatorStore.java (+9/-8)
src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java (+10/-24)
src/main/java/com/akiban/qp/persistitadapter/PersistitGroupRow.java (+1/-0)
src/main/java/com/akiban/qp/persistitadapter/indexrow/PersistitIndexRow.java (+1/-1)
src/main/java/com/akiban/qp/row/AbstractRow.java (+5/-0)
src/main/java/com/akiban/server/PersistitAccumulatorTableStatusCache.java (+52/-23)
src/main/java/com/akiban/server/TableStatus.java (+8/-8)
src/main/java/com/akiban/server/manage/ManageMXBean.java (+0/-6)
src/main/java/com/akiban/server/manage/ManageMXBeanImpl.java (+0/-22)
src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java (+1/-1)
src/main/java/com/akiban/server/service/dxl/BasicDMLFunctions.java (+7/-33)
src/main/java/com/akiban/server/store/AbstractStore.java (+487/-0)
src/main/java/com/akiban/server/store/DelegatingStore.java (+57/-30)
src/main/java/com/akiban/server/store/PersistitStore.java (+126/-618)
src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java (+1/-5)
src/main/java/com/akiban/server/store/Store.java (+27/-42)
src/main/java/com/akiban/server/store/statistics/IndexStatisticsServiceImpl.java (+2/-2)
src/main/java/com/akiban/server/store/statistics/PersistitStoreIndexStatistics.java (+3/-0)
src/test/java/com/akiban/server/test/it/keyupdate/FixCountStarIT.java (+1/-1)
src/test/java/com/akiban/server/test/it/rowtests/ObjectToKeyIT.java (+1/-1)
src/test/java/com/akiban/server/test/it/store/AbstractScanBase.java (+2/-2)
To merge this branch: bzr merge lp:~nwilliams/akiban-server/abstract-store
Reviewer Review Type Date Requested Status
Thomas Jones-Low Needs Fixing
Mike McMahon Approve
Review via email: mp+164745@code.launchpad.net

Description of the change

Pull general methods from PersistitStore into AbstractStore and cleanup PersistitException on interfaces.

Particularly, don't declare to throw anything on TableStatus or Store. Minor cascading cleanup that removes try/catch/wrap from higher level classes down into implementations.

Additionally, remove deferred indexing methods as they have been broken for a long time (bug767737) and are unused.

To post a comment you must log in.
Revision history for this message
Mike McMahon (mmcm) wrote :

Looks as described.

review: Approve
Revision history for this message
Thomas Jones-Low (tjoneslo) wrote :

There were 2 failures during build/test:

* job server-build failed at build number 4030: http://172.16.20.104:8080/job/server-build/4030/

* view must-pass failed: server-build is yellow

review: Needs Fixing
Revision history for this message
Thomas Jones-Low (tjoneslo) wrote :

Build system failure, not merge proposal failure. Trying again.

Revision history for this message
Thomas Jones-Low (tjoneslo) wrote :

There were 2 failures during build/test:

* job server-build failed at build number 4032: http://172.16.20.104:8080/job/server-build/4032/

* view must-pass failed: server-build is yellow

review: Needs Fixing
Revision history for this message
Nathan Williams (nwilliams) wrote :

Manually ran ITs on sleepy.

Preview Diff

[H/L] Next/Prev Comment, [J/K] Next/Prev File, [N/P] Next/Prev Hunk
1=== modified file 'src/main/java/com/akiban/ais/model/UserTable.java'
2--- src/main/java/com/akiban/ais/model/UserTable.java 2013-04-07 01:22:07 +0000
3+++ src/main/java/com/akiban/ais/model/UserTable.java 2013-05-20 14:47:34 +0000
4@@ -168,6 +168,10 @@
5 return Collections.unmodifiableList(candidateChildJoins);
6 }
7
8+ public boolean hasChildren() {
9+ return !getCandidateChildJoins().isEmpty();
10+ }
11+
12 public Join getParentJoin()
13 {
14 Join parentJoin = null;
15
16=== modified file 'src/main/java/com/akiban/qp/persistitadapter/OneTableRowCollector.java'
17--- src/main/java/com/akiban/qp/persistitadapter/OneTableRowCollector.java 2013-03-22 20:05:57 +0000
18+++ src/main/java/com/akiban/qp/persistitadapter/OneTableRowCollector.java 2013-05-20 14:47:34 +0000
19@@ -26,15 +26,13 @@
20 import com.akiban.server.api.dml.scan.NewRow;
21 import com.akiban.server.rowdata.RowData;
22 import com.akiban.server.rowdata.RowDef;
23-import com.akiban.server.service.config.ConfigurationService;
24 import com.akiban.server.service.session.Session;
25-import com.akiban.server.store.PersistitStore;
26+import com.akiban.server.store.Store;
27
28 public class OneTableRowCollector extends OperatorBasedRowCollector
29 {
30- OneTableRowCollector(ConfigurationService config,
31- Session session,
32- PersistitStore store,
33+ OneTableRowCollector(Session session,
34+ Store store,
35 RowDef rowDef,
36 int indexId,
37 int scanFlags,
38@@ -43,7 +41,7 @@
39 RowData end,
40 ColumnSelector endColumns)
41 {
42- super(store, session, config);
43+ super(store, session);
44 // rootmostQueryTable
45 queryRootTable = rowDef.userTable();
46 queryRootType = schema.userTableRowType(queryRootTable);
47
48=== modified file 'src/main/java/com/akiban/qp/persistitadapter/OperatorBasedRowCollector.java'
49--- src/main/java/com/akiban/qp/persistitadapter/OperatorBasedRowCollector.java 2013-04-30 22:35:43 +0000
50+++ src/main/java/com/akiban/qp/persistitadapter/OperatorBasedRowCollector.java 2013-05-20 14:47:34 +0000
51@@ -23,6 +23,8 @@
52 import com.akiban.qp.operator.Limit;
53 import com.akiban.qp.operator.Operator;
54 import com.akiban.qp.operator.SimpleQueryContext;
55+import com.akiban.qp.operator.StoreAdapter;
56+import com.akiban.qp.row.AbstractRow;
57 import com.akiban.qp.row.Row;
58 import com.akiban.qp.rowtype.*;
59 import com.akiban.qp.rowtype.Schema;
60@@ -38,6 +40,7 @@
61 import com.akiban.server.service.session.Session;
62 import com.akiban.server.store.PersistitStore;
63 import com.akiban.server.store.RowCollector;
64+import com.akiban.server.store.Store;
65 import com.akiban.server.types3.Types3Switch;
66 import com.akiban.util.GrowableByteBuffer;
67 import com.akiban.util.ShareHolder;
68@@ -78,12 +81,12 @@
69 // the current row across these two invocations.
70 boolean wasHeld = false;
71 boolean wroteToPayload = false;
72- PersistitGroupRow row;
73+ AbstractRow row;
74 if (currentRow.isEmpty()) {
75- row = (PersistitGroupRow) cursor.next();
76+ row = (AbstractRow) cursor.next();
77 } else {
78 wasHeld = true;
79- row = (PersistitGroupRow) currentRow.get();
80+ row = (AbstractRow) currentRow.get();
81 currentRow.release();
82 }
83 if (row == null) {
84@@ -117,7 +120,7 @@
85 public RowData collectNextRow()
86 {
87 RowData rowData = null;
88- PersistitGroupRow row = (PersistitGroupRow) cursor.next();
89+ AbstractRow row = (AbstractRow) cursor.next();
90 if (row == null) {
91 close();
92 } else {
93@@ -196,9 +199,8 @@
94
95 // OperatorBasedRowCollector interface
96
97- public static OperatorBasedRowCollector newCollector(ConfigurationService config,
98- Session session,
99- PersistitStore store,
100+ public static OperatorBasedRowCollector newCollector(Session session,
101+ Store store,
102 int scanFlags,
103 RowDef rowDef,
104 int indexId,
105@@ -217,8 +219,7 @@
106 throw new IllegalArgumentException("Must scan a UserTable: " + rowDef);
107 }
108 OperatorBasedRowCollector rowCollector =
109- new OneTableRowCollector(config,
110- session,
111+ new OneTableRowCollector(session,
112 store,
113 rowDef,
114 indexId,
115@@ -234,12 +235,10 @@
116 return rowCollector;
117 }
118
119- protected OperatorBasedRowCollector(PersistitStore store, Session session, ConfigurationService config)
120+ protected OperatorBasedRowCollector(Store store, Session session)
121 {
122 this.schema = SchemaCache.globalSchema(store.getAIS(session));
123- // Passing null to PersistitAdapter's TreeService argument. TreeService is only needed for sorting,
124- // which OBRC doesn't use.
125- this.adapter = new PersistitAdapter(schema, store, null, session, config);
126+ this.adapter = store.createAdapter(session, schema);
127 this.rowCollectorId = idCounter.getAndIncrement();
128 }
129
130@@ -397,7 +396,7 @@
131
132 private long rowCollectorId;
133 protected final Schema schema;
134- protected PersistitAdapter adapter;
135+ protected StoreAdapter adapter;
136 protected UserTable queryRootTable;
137 protected UserTableRowType queryRootType;
138 protected TableIndex predicateIndex;
139
140=== modified file 'src/main/java/com/akiban/qp/persistitadapter/OperatorStore.java'
141--- src/main/java/com/akiban/qp/persistitadapter/OperatorStore.java 2013-04-30 22:35:43 +0000
142+++ src/main/java/com/akiban/qp/persistitadapter/OperatorStore.java 2013-05-20 14:47:34 +0000
143@@ -48,7 +48,6 @@
144 import com.akiban.server.store.SchemaManager;
145 import com.akiban.server.types.ToObjectValueTarget;
146 import com.akiban.server.types.ValueSource;
147-import com.akiban.server.types3.Types3Switch;
148 import com.akiban.sql.optimizer.rule.PlanGenerator;
149 import com.akiban.util.tap.InOutTap;
150 import com.akiban.util.tap.PointTap;
151@@ -86,7 +85,6 @@
152
153 @Override
154 public void updateRow(Session session, RowData oldRowData, RowData newRowData, ColumnSelector columnSelector, Index[] indexes)
155- throws PersistitException
156 {
157 if(indexes != null) {
158 throw new IllegalStateException("Unexpected indexes: " + Arrays.toString(indexes));
159@@ -169,7 +167,7 @@
160 }
161
162 @Override
163- public void writeRow(Session session, RowData rowData) throws PersistitException {
164+ public void writeRow(Session session, RowData rowData) {
165 INSERT_TOTAL.in();
166 INSERT_MAINTENANCE.in();
167 try {
168@@ -194,7 +192,7 @@
169 }
170
171 @Override
172- public void deleteRow(Session session, RowData rowData, boolean deleteIndexes, boolean cascadeDelete) throws PersistitException {
173+ public void deleteRow(Session session, RowData rowData, boolean deleteIndexes, boolean cascadeDelete) {
174 DELETE_TOTAL.in();
175 DELETE_MAINTENANCE.in();
176 try {
177@@ -288,14 +286,14 @@
178 BitSet columnDifferences,
179 OperatorStoreGIHandler handler,
180 OperatorStoreGIHandler.Action action)
181- throws PersistitException
182 {
183 UserTable userTable = ais.getUserTable(rowData.getRowDefId());
184 if(canSkipMaintenance(userTable)) {
185 return;
186 }
187- Exchange hEx = adapter.takeExchange(userTable.getGroup());
188+ Exchange hEx = null;
189 try {
190+ hEx = adapter.takeExchange(userTable.getGroup());
191 // the "false" at the end of constructHKey toggles whether the RowData should be modified to increment
192 // the hidden PK field, if there is one. For PK-less rows, this field have already been incremented by now,
193 // so we don't want to increment it again
194@@ -316,8 +314,12 @@
195 SKIP_MAINTENANCE.hit();
196 }
197 }
198+ } catch(PersistitException e) {
199+ throw PersistitAdapter.wrapPersistitException(session, e);
200 } finally {
201- adapter.returnExchange(hEx);
202+ if(hEx != null) {
203+ adapter.returnExchange(hEx);
204+ }
205 }
206 }
207
208@@ -357,7 +359,6 @@
209 AkibanInformationSchema ais,
210 PersistitAdapter adapter,
211 RowData rowData)
212- throws PersistitException
213 {
214 UserTable uTable = ais.getUserTable(rowData.getRowDefId());
215
216
217=== modified file 'src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java'
218--- src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java 2013-04-11 05:51:16 +0000
219+++ src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java 2013-05-20 14:47:34 +0000
220@@ -129,10 +129,6 @@
221 } catch (InvalidOperationException e) {
222 rollbackIfNeeded(e);
223 throw e;
224- } catch (PersistitException e) {
225- rollbackIfNeeded(e);
226- handlePersistitException(e);
227- assert false;
228 }
229 finally {
230 leaveUpdateStep(oldStep);
231@@ -149,10 +145,6 @@
232 } catch (InvalidOperationException e) {
233 rollbackIfNeeded(e);
234 throw e;
235- } catch (PersistitException e) {
236- rollbackIfNeeded(e);
237- handlePersistitException(e);
238- assert false;
239 }
240 finally {
241 leaveUpdateStep(oldStep);
242@@ -170,10 +162,6 @@
243 } catch (InvalidOperationException e) {
244 rollbackIfNeeded(e);
245 throw e;
246- } catch (PersistitException e) {
247- rollbackIfNeeded(e);
248- handlePersistitException(e);
249- assert false;
250 }
251 finally {
252 leaveUpdateStep(oldStep);
253@@ -203,10 +191,6 @@
254 } catch (InvalidOperationException e) {
255 rollbackIfNeeded(e);
256 throw e;
257- } catch (PersistitException e) {
258- rollbackIfNeeded(e);
259- handlePersistitException(e);
260- assert false;
261 }
262 finally {
263 leaveUpdateStep(oldStep);
264@@ -216,11 +200,7 @@
265 @Override
266 public long rowCount(RowType tableType) {
267 RowDef rowDef = tableType.userTable().rowDef();
268- try {
269- return rowDef.getTableStatus().getRowCount();
270- } catch(PersistitInterruptedException e) {
271- throw new QueryCanceledException(getSession());
272- }
273+ return rowDef.getTableStatus().getRowCount();
274 }
275
276 @Override
277@@ -235,7 +215,7 @@
278 key = persistitKeyValueSource.key();
279 depth = persistitKeyValueSource.depth();
280 } else {
281- key = persistit.getKey();
282+ key = persistit.createKey();
283 collator.append(key, valueSource.getString());
284 depth = 0;
285 }
286@@ -325,7 +305,10 @@
287 public static boolean isFromInterruption(Exception e) {
288 Throwable cause = e.getCause();
289 return (e instanceof PersistitInterruptedException) ||
290- ((cause != null) && (cause instanceof InterruptedIOException || cause instanceof InterruptedException));
291+ ((cause != null) &&
292+ (cause instanceof PersistitInterruptedException ||
293+ cause instanceof InterruptedIOException ||
294+ cause instanceof InterruptedException));
295 }
296
297 public static RuntimeException wrapPersistitException(Session session, PersistitException e)
298@@ -418,7 +401,10 @@
299
300 // For use by this class
301 private void rollbackIfNeeded(Exception e) {
302- if((e instanceof DuplicateKeyException) || (e instanceof PersistitException) || isFromInterruption(e)) {
303+ if((e instanceof DuplicateKeyException) ||
304+ (e instanceof PersistitException) ||
305+ (e instanceof PersistitAdapterException) ||
306+ isFromInterruption(e)) {
307 Transaction txn = transaction();
308 if(txn.isActive()) {
309 txn.rollback();
310
311=== modified file 'src/main/java/com/akiban/qp/persistitadapter/PersistitGroupRow.java'
312--- src/main/java/com/akiban/qp/persistitadapter/PersistitGroupRow.java 2013-03-22 20:05:57 +0000
313+++ src/main/java/com/akiban/qp/persistitadapter/PersistitGroupRow.java 2013-05-20 14:47:34 +0000
314@@ -159,6 +159,7 @@
315 } while (exception != null);
316 }
317
318+ @Override
319 public RowData rowData()
320 {
321 return rowData;
322
323=== modified file 'src/main/java/com/akiban/qp/persistitadapter/indexrow/PersistitIndexRow.java'
324--- src/main/java/com/akiban/qp/persistitadapter/indexrow/PersistitIndexRow.java 2013-03-22 20:05:57 +0000
325+++ src/main/java/com/akiban/qp/persistitadapter/indexrow/PersistitIndexRow.java 2013-05-20 14:47:34 +0000
326@@ -128,7 +128,7 @@
327 protected PersistitIndexRow(PersistitAdapter adapter, IndexRowType indexRowType)
328 {
329 super(adapter);
330- this.keyState = adapter.persistit().getKey();
331+ this.keyState = adapter.persistit().createKey();
332 resetForWrite(indexRowType.index(), keyState);
333 this.indexRowType = indexRowType;
334 this.leafmostTable = (UserTable) index.leafMostTable();
335
336=== modified file 'src/main/java/com/akiban/qp/row/AbstractRow.java'
337--- src/main/java/com/akiban/qp/row/AbstractRow.java 2013-03-22 20:05:57 +0000
338+++ src/main/java/com/akiban/qp/row/AbstractRow.java 2013-05-20 14:47:34 +0000
339@@ -22,6 +22,7 @@
340 import com.akiban.qp.rowtype.IndexRowType;
341 import com.akiban.qp.rowtype.RowType;
342 import com.akiban.server.Quote;
343+import com.akiban.server.rowdata.RowData;
344 import com.akiban.server.types.ValueSource;
345 import com.akiban.server.types.util.ValueSources;
346 import com.akiban.server.types3.TClass;
347@@ -166,6 +167,10 @@
348 return builder.toString();
349 }
350
351+ public RowData rowData() {
352+ throw new UnsupportedOperationException();
353+ }
354+
355 // for use by subclasses
356 protected void afterRelease() {}
357 protected void beforeAcquire() {}
358
359=== modified file 'src/main/java/com/akiban/server/PersistitAccumulatorTableStatusCache.java'
360--- src/main/java/com/akiban/server/PersistitAccumulatorTableStatusCache.java 2013-04-11 06:15:45 +0000
361+++ src/main/java/com/akiban/server/PersistitAccumulatorTableStatusCache.java 2013-05-20 14:47:34 +0000
362@@ -18,6 +18,7 @@
363 package com.akiban.server;
364
365 import com.akiban.qp.memoryadapter.MemoryTableFactory;
366+import com.akiban.qp.persistitadapter.PersistitAdapter;
367 import com.akiban.server.error.PersistitAdapterException;
368 import com.akiban.server.rowdata.IndexDef;
369 import com.akiban.server.rowdata.RowDef;
370@@ -97,18 +98,30 @@
371 }
372
373 @Override
374- public long getAutoIncrement() throws PersistitInterruptedException {
375- return autoIncrement.getSnapshot();
376- }
377-
378- @Override
379- public int getOrdinal() throws PersistitInterruptedException {
380- return (int) ordinal.getSnapshot();
381- }
382-
383- @Override
384- public long getRowCount() throws PersistitInterruptedException {
385- return rowCount.getSnapshot();
386+ public long getAutoIncrement() {
387+ try {
388+ return autoIncrement.getSnapshot();
389+ } catch(PersistitInterruptedException e) {
390+ throw PersistitAdapter.wrapPersistitException(null, e);
391+ }
392+ }
393+
394+ @Override
395+ public int getOrdinal() {
396+ try {
397+ return (int) ordinal.getSnapshot();
398+ } catch(PersistitInterruptedException e) {
399+ throw PersistitAdapter.wrapPersistitException(null, e);
400+ }
401+ }
402+
403+ @Override
404+ public long getRowCount() {
405+ try {
406+ return rowCount.getSnapshot();
407+ } catch(PersistitInterruptedException e) {
408+ throw PersistitAdapter.wrapPersistitException(null, e);
409+ }
410 }
411
412 @Override
413@@ -127,8 +140,12 @@
414 }
415
416 @Override
417- public long getUniqueID() throws PersistitInterruptedException {
418- return uniqueID.getSnapshot();
419+ public long getUniqueID() {
420+ try {
421+ return uniqueID.getSnapshot();
422+ } catch(PersistitInterruptedException e) {
423+ throw PersistitAdapter.wrapPersistitException(null, e);
424+ }
425 }
426
427 @Override
428@@ -151,23 +168,31 @@
429 rowCount.sumAdd(count);
430 }
431
432- public void setOrdinal(int ordinal) throws PersistitInterruptedException {
433- this.ordinal.set(ordinal);
434+ public void setOrdinal(int ordinal) {
435+ try {
436+ this.ordinal.set(ordinal);
437+ } catch(PersistitInterruptedException e) {
438+ throw PersistitAdapter.wrapPersistitException(null, e);
439+ }
440 }
441
442 @Override
443- public long createNewUniqueID() throws PersistitInterruptedException {
444+ public long createNewUniqueID() {
445 return uniqueID.seqAllocate();
446 }
447
448 @Override
449- public void truncate() throws PersistitInterruptedException {
450- internalSetRowCount(0);
451- internalSetAutoIncrement(0, true);
452+ public void truncate() {
453+ try {
454+ internalSetRowCount(0);
455+ internalSetAutoIncrement(0, true);
456+ } catch(PersistitInterruptedException e) {
457+ throw PersistitAdapter.wrapPersistitException(null, e);
458+ }
459 }
460
461 @Override
462- public void setAutoIncrement(long value) throws PersistitInterruptedException {
463+ public void setAutoIncrement(long value) {
464 internalSetAutoIncrement(value, false);
465 }
466
467@@ -189,8 +214,12 @@
468 rowCount.set(rowCountValue);
469 }
470
471- private void internalSetAutoIncrement(long autoIncrementValue, boolean evenIfLess) throws PersistitInterruptedException {
472- autoIncrement.set(autoIncrementValue, evenIfLess);
473+ private void internalSetAutoIncrement(long autoIncrementValue, boolean evenIfLess) {
474+ try {
475+ autoIncrement.set(autoIncrementValue, evenIfLess);
476+ } catch(PersistitInterruptedException e) {
477+ throw PersistitAdapter.wrapPersistitException(null, e);
478+ }
479 }
480 }
481
482
483=== modified file 'src/main/java/com/akiban/server/TableStatus.java'
484--- src/main/java/com/akiban/server/TableStatus.java 2013-04-11 06:15:45 +0000
485+++ src/main/java/com/akiban/server/TableStatus.java 2013-05-20 14:47:34 +0000
486@@ -34,34 +34,34 @@
487 void rowsWritten(long count);
488
489 /** Reset, but do not remove, the state of a table. */
490- void truncate() throws PersistitInterruptedException;
491+ void truncate();
492
493 /** Set the auto-increment value of a given table. */
494- void setAutoIncrement(long value) throws PersistitInterruptedException;
495+ void setAutoIncrement(long value);
496
497 /** Set the RowDef of a given table.*/
498 void setRowDef(RowDef rowDef);
499
500 /** Create a brand new, unique ID for the given table. */
501- long createNewUniqueID() throws PersistitInterruptedException;
502+ long createNewUniqueID();
503
504 /** Set the ordinal value of a given table. */
505- void setOrdinal(int value) throws PersistitInterruptedException;
506+ void setOrdinal(int value);
507
508 /**
509 * @return Current auto-increment value of the assocated table.
510 */
511- long getAutoIncrement() throws PersistitInterruptedException;
512+ long getAutoIncrement();
513
514 /**
515 * @return Ordinal of the associated table.
516 */
517- int getOrdinal() throws PersistitInterruptedException;
518+ int getOrdinal();
519
520 /**
521 * @return Current number of rows in the associated table.
522 */
523- long getRowCount() throws PersistitInterruptedException;
524+ long getRowCount();
525
526 /**
527 * @return Approximate number of rows in the associated table.
528@@ -71,7 +71,7 @@
529 /**
530 * @return The <b>last</b> unique value used for the associated table.
531 */
532- long getUniqueID() throws PersistitInterruptedException;
533+ long getUniqueID();
534
535 /** @return The table ID this status is for */
536 int getTableID();
537
538=== modified file 'src/main/java/com/akiban/server/manage/ManageMXBean.java'
539--- src/main/java/com/akiban/server/manage/ManageMXBean.java 2013-03-22 20:05:57 +0000
540+++ src/main/java/com/akiban/server/manage/ManageMXBean.java 2013-05-20 14:47:34 +0000
541@@ -25,15 +25,9 @@
542
543 int getJmxPort();
544
545- boolean isDeferIndexesEnabled();
546-
547- void setDeferIndexes(final boolean defer);
548-
549 void buildIndexes(final String arg, final boolean deferIndexes);
550
551 void deleteIndexes(final String arg);
552
553- void flushIndexes();
554-
555 String getVersionString();
556 }
557
558=== modified file 'src/main/java/com/akiban/server/manage/ManageMXBeanImpl.java'
559--- src/main/java/com/akiban/server/manage/ManageMXBeanImpl.java 2013-03-22 20:05:57 +0000
560+++ src/main/java/com/akiban/server/manage/ManageMXBeanImpl.java 2013-05-20 14:47:34 +0000
561@@ -52,16 +52,6 @@
562 }
563
564 @Override
565- public boolean isDeferIndexesEnabled() {
566- return getStore().isDeferIndexes();
567- }
568-
569- @Override
570- public void setDeferIndexes(final boolean defer) {
571- getStore().setDeferIndexes(defer);
572- }
573-
574- @Override
575 public void buildIndexes(final String arg, final boolean deferIndexes) {
576 Session session = createSession();
577 try {
578@@ -88,18 +78,6 @@
579 }
580
581 @Override
582- public void flushIndexes() {
583- Session session = createSession();
584- try {
585- getStore().flushIndexes(session);
586- } catch(Exception t) {
587- throw new RuntimeException(t);
588- } finally {
589- session.close();
590- }
591- }
592-
593- @Override
594 public String getVersionString() {
595 return AkServer.VERSION_STRING;
596 }
597
598=== modified file 'src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java'
599--- src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-04-22 02:00:55 +0000
600+++ src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-05-20 14:47:34 +0000
601@@ -1161,7 +1161,7 @@
602 if (expected != actual) {
603 PersistitStore pStore = this.store().getPersistitStore();
604 if (index.isTableIndex()) {
605- pStore.getTableStatus(((TableIndex) index).getTable()).setRowCount(actual);
606+ index.leafMostTable().rowDef().getTableStatus().setRowCount(actual);
607 }
608 else {
609 final Exchange ex = pStore.getExchange(session, index);
610
611=== modified file 'src/main/java/com/akiban/server/service/dxl/BasicDMLFunctions.java'
612--- src/main/java/com/akiban/server/service/dxl/BasicDMLFunctions.java 2013-03-22 20:05:57 +0000
613+++ src/main/java/com/akiban/server/service/dxl/BasicDMLFunctions.java 2013-05-20 14:47:34 +0000
614@@ -581,22 +581,14 @@
615 {
616 logger.trace("writing a row");
617 final RowData rowData = niceRowToRowData(row);
618- try {
619- store().writeRow(session, rowData);
620- } catch (PersistitException ex) {
621- throw new PersistitAdapterException(ex);
622- }
623+ store().writeRow(session, rowData);
624 }
625
626 @Override
627 public void writeRows(Session session, List<RowData> rows) {
628 logger.trace("writing {} rows", rows.size());
629- try {
630- for(RowData rowData : rows) {
631- store().writeRow(session, rowData);
632- }
633- } catch (PersistitException ex) {
634- throw new PersistitAdapterException(ex);
635+ for(RowData rowData : rows) {
636+ store().writeRow(session, rowData);
637 }
638 }
639
640@@ -605,11 +597,7 @@
641 {
642 logger.trace("deleting a row (cascade: {})", cascadeDelete);
643 final RowData rowData = niceRowToRowData(row);
644- try {
645- store().deleteRow(session, rowData, true, cascadeDelete);
646- } catch (PersistitException ex) {
647- throw new PersistitAdapterException(ex);
648- }
649+ store().deleteRow(session, rowData, true, cascadeDelete);
650 }
651
652 private RowData niceRowToRowData(NewRow row)
653@@ -636,12 +624,7 @@
654 tableId
655 );
656
657- try {
658- store().updateRow(session, oldData, newData, columnSelector, null);
659- } catch (PersistitException ex) {
660- throw new PersistitAdapterException(ex);
661- }
662-
663+ store().updateRow(session, oldData, newData, columnSelector, null);
664 }
665
666 private void checkForModifiedCursors(
667@@ -749,12 +732,7 @@
668 final UserTable utable = table.isUserTable() ? (UserTable)table : null;
669
670 if(utable == null || canFastTruncate(session, utable)) {
671- try {
672- store().truncateGroup(session, table.getGroup());
673- } catch (PersistitException ex) {
674- throw new PersistitAdapterException(ex);
675- }
676-
677+ store().truncateGroup(session, table.getGroup());
678 return;
679 }
680
681@@ -810,11 +788,7 @@
682 thrown = e;
683 }
684 }
685- try {
686- store().truncateTableStatus(session, tableId);
687- } catch (PersistitException ex) {
688- throw new PersistitAdapterException(ex);
689- }
690+ store().truncateTableStatus(session, tableId);
691 if (thrown != null) {
692 throw thrown;
693 }
694
695=== added file 'src/main/java/com/akiban/server/store/AbstractStore.java'
696--- src/main/java/com/akiban/server/store/AbstractStore.java 1970-01-01 00:00:00 +0000
697+++ src/main/java/com/akiban/server/store/AbstractStore.java 2013-05-20 14:47:34 +0000
698@@ -0,0 +1,487 @@
699+/**
700+ * Copyright (C) 2009-2013 Akiban Technologies, Inc.
701+ *
702+ * This program is free software: you can redistribute it and/or modify
703+ * it under the terms of the GNU Affero General Public License as published by
704+ * the Free Software Foundation, either version 3 of the License, or
705+ * (at your option) any later version.
706+ *
707+ * This program is distributed in the hope that it will be useful,
708+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
709+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
710+ * GNU Affero General Public License for more details.
711+ *
712+ * You should have received a copy of the GNU Affero General Public License
713+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
714+ */
715+
716+package com.akiban.server.store;
717+
718+import com.akiban.ais.model.Group;
719+import com.akiban.ais.model.Index;
720+import com.akiban.ais.model.NopVisitor;
721+import com.akiban.ais.model.Table;
722+import com.akiban.ais.model.TableName;
723+import com.akiban.ais.model.UserTable;
724+import com.akiban.qp.persistitadapter.OperatorBasedRowCollector;
725+import com.akiban.server.TableStatistics;
726+import com.akiban.server.TableStatus;
727+import com.akiban.server.api.dml.ColumnSelector;
728+import com.akiban.server.api.dml.scan.ScanLimit;
729+import com.akiban.server.error.CursorCloseBadException;
730+import com.akiban.server.error.CursorIsUnknownException;
731+import com.akiban.server.error.NoSuchTableException;
732+import com.akiban.server.error.RowDefNotFoundException;
733+import com.akiban.server.rowdata.IndexDef;
734+import com.akiban.server.rowdata.RowData;
735+import com.akiban.server.rowdata.RowDef;
736+import com.akiban.server.service.session.Session;
737+import com.akiban.server.service.tree.TreeLink;
738+import com.akiban.server.store.statistics.Histogram;
739+import com.akiban.server.store.statistics.HistogramEntry;
740+import com.akiban.server.store.statistics.IndexStatistics;
741+import com.akiban.server.store.statistics.IndexStatisticsService;
742+import com.akiban.util.tap.InOutTap;
743+import com.akiban.util.tap.Tap;
744+import com.persistit.Key;
745+import org.slf4j.Logger;
746+import org.slf4j.LoggerFactory;
747+
748+import java.util.ArrayList;
749+import java.util.Arrays;
750+import java.util.BitSet;
751+import java.util.Collection;
752+import java.util.Collections;
753+import java.util.List;
754+
755+public abstract class AbstractStore implements Store {
756+ private static final Logger LOG = LoggerFactory.getLogger(AbstractStore.class.getName());
757+ private static final InOutTap NEW_COLLECTOR_TAP = Tap.createTimer("read: new_collector");
758+ private static final Session.MapKey<Integer,List<RowCollector>> COLLECTORS = Session.MapKey.mapNamed("collectors");
759+
760+ protected IndexStatisticsService indexStatisticsService;
761+
762+ //
763+ // AbstractStore
764+ //
765+
766+ protected RowDef rowDefFromExplicitOrId(Session session, RowData rowData) {
767+ RowDef rowDef = rowData.getExplicitRowDef();
768+ if(rowDef == null) {
769+ rowDef = getRowDef(session, rowData.getRowDefId());
770+ }
771+ return rowDef;
772+ }
773+
774+ protected boolean hasNullIndexSegments(RowData rowData, Index index)
775+ {
776+ IndexDef indexDef = index.indexDef();
777+ assert indexDef.getRowDef().getRowDefId() == rowData.getRowDefId();
778+ for (int i : indexDef.getFields()) {
779+ if (rowData.isNull(i)) {
780+ return true;
781+ }
782+ }
783+ return false;
784+ }
785+
786+ /** Convert from new-format histogram to old for adapter. */
787+ protected TableStatistics.Histogram indexStatisticsToHistogram(Session session, Index index, Key key) {
788+ IndexStatistics stats = indexStatisticsService.getIndexStatistics(session, index);
789+ if (stats == null) {
790+ return null;
791+ }
792+ Histogram fromHistogram = stats.getHistogram(0, index.getKeyColumns().size());
793+ if (fromHistogram == null) {
794+ return null;
795+ }
796+ IndexDef indexDef = index.indexDef();
797+ RowDef indexRowDef = indexDef.getRowDef();
798+ TableStatistics.Histogram toHistogram = new TableStatistics.Histogram(index.getIndexId());
799+ RowData indexRowData = new RowData(new byte[4096]);
800+ Object[] indexValues = new Object[indexRowDef.getFieldCount()];
801+ long count = 0;
802+ for (HistogramEntry entry : fromHistogram.getEntries()) {
803+ // Decode the key.
804+ int keylen = entry.getKeyBytes().length;
805+ System.arraycopy(entry.getKeyBytes(), 0, key.getEncodedBytes(), 0, keylen);
806+ key.setEncodedSize(keylen);
807+ key.indexTo(0);
808+ int depth = key.getDepth();
809+ // Copy key fields to index row.
810+ for (int field : indexDef.getFields()) {
811+ if (--depth >= 0) {
812+ indexValues[field] = key.decode();
813+ } else {
814+ indexValues[field] = null;
815+ }
816+ }
817+ indexRowData.createRow(indexRowDef, indexValues);
818+ // Partial counts to running total less than key.
819+ count += entry.getLessCount();
820+ toHistogram.addSample(new TableStatistics.HistogramSample(indexRowData.copy(), count));
821+ count += entry.getEqualCount();
822+ }
823+ // Add final entry with all nulls.
824+ Arrays.fill(indexValues, null);
825+ indexRowData.createRow(indexRowDef, indexValues);
826+ toHistogram.addSample(new TableStatistics.HistogramSample(indexRowData.copy(), count));
827+ return toHistogram;
828+ }
829+
830+ protected static boolean bytesEqual(byte[] a, int aoffset, int asize, byte[] b, int boffset, int bsize) {
831+ if (asize != bsize) {
832+ return false;
833+ }
834+ for (int i = 0; i < asize; i++) {
835+ if (a[i + aoffset] != b[i + boffset]) {
836+ return false;
837+ }
838+ }
839+ return true;
840+ }
841+
842+ protected static boolean fieldsEqual(RowDef rowDef, RowData a, RowData b, int[] fieldIndexes)
843+ {
844+ for (int fieldIndex : fieldIndexes) {
845+ long aloc = rowDef.fieldLocation(a, fieldIndex);
846+ long bloc = rowDef.fieldLocation(b, fieldIndex);
847+ if (!bytesEqual(a.getBytes(), (int) aloc, (int) (aloc >>> 32),
848+ b.getBytes(), (int) bloc, (int) (bloc >>> 32))) {
849+ return false;
850+ }
851+ }
852+ return true;
853+ }
854+
855+ protected static boolean fieldEqual(RowDef rowDef, RowData a, RowData b, int fieldPosition)
856+ {
857+ long aloc = rowDef.fieldLocation(a, fieldPosition);
858+ long bloc = rowDef.fieldLocation(b, fieldPosition);
859+ return bytesEqual(a.getBytes(), (int) aloc, (int) (aloc >>> 32),
860+ b.getBytes(), (int) bloc, (int) (bloc >>> 32));
861+ }
862+
863+ protected BitSet analyzeFieldChanges(Session session, RowDef rowDef, RowData oldRow, RowData newRow)
864+ {
865+ BitSet tablesRequiringHKeyMaintenance;
866+ assert oldRow.getRowDefId() == newRow.getRowDefId();
867+ int fields = rowDef.getFieldCount();
868+ // Find the PK and FK fields
869+ BitSet keyField = new BitSet(fields);
870+ for (int pkFieldPosition : rowDef.getPKIndex().indexDef().getFields()) {
871+ keyField.set(pkFieldPosition, true);
872+ }
873+ for (int fkFieldPosition : rowDef.getParentJoinFields()) {
874+ keyField.set(fkFieldPosition, true);
875+ }
876+ // Find whether and where key fields differ
877+ boolean allEqual = true;
878+ for (int keyFieldPosition = keyField.nextSetBit(0);
879+ allEqual && keyFieldPosition >= 0;
880+ keyFieldPosition = keyField.nextSetBit(keyFieldPosition + 1)) {
881+ boolean fieldEqual = fieldEqual(rowDef, oldRow, newRow, keyFieldPosition);
882+ if (!fieldEqual) {
883+ allEqual = false;
884+ }
885+ }
886+ if (allEqual) {
887+ tablesRequiringHKeyMaintenance = null;
888+ } else {
889+ // A PK or FK field has changed, so the update has to be done as delete/insert. To minimize hkey
890+ // propagation work, find which tables (descendents of the updated table) are affected by hkey
891+ // changes.
892+ tablesRequiringHKeyMaintenance = hKeyDependentTableOrdinals(session, oldRow.getRowDefId());
893+ }
894+ return tablesRequiringHKeyMaintenance;
895+ }
896+
897+ private BitSet hKeyDependentTableOrdinals(Session session, int rowDefId)
898+ {
899+ RowDef rowDef = getRowDef(session, rowDefId);
900+ UserTable table = rowDef.userTable();
901+ BitSet ordinals = new BitSet();
902+ for (UserTable hKeyDependentTable : table.hKeyDependentTables()) {
903+ int ordinal = hKeyDependentTable.rowDef().getOrdinal();
904+ ordinals.set(ordinal, true);
905+ }
906+ return ordinals;
907+ }
908+
909+
910+ //
911+ // Store methods
912+ //
913+
914+ @Override
915+ public RowDef getRowDef(Session session, int rowDefID) {
916+ Table table = getAIS(session).getUserTable(rowDefID);
917+ if(table == null) {
918+ throw new RowDefNotFoundException(rowDefID);
919+ }
920+ return table.rowDef();
921+ }
922+
923+ @Override
924+ public RowDef getRowDef(Session session, TableName tableName) {
925+ Table table = getAIS(session).getTable(tableName);
926+ if(table == null) {
927+ throw new NoSuchTableException(tableName);
928+ }
929+ return table.rowDef();
930+ }
931+
932+ @Override
933+ public RowCollector newRowCollector(Session session,
934+ int scanFlags,
935+ int rowDefId,
936+ int indexId,
937+ byte[] columnBitMap,
938+ RowData start,
939+ ColumnSelector startColumns,
940+ RowData end,
941+ ColumnSelector endColumns,
942+ ScanLimit scanLimit)
943+ {
944+ NEW_COLLECTOR_TAP.in();
945+ RowCollector rc;
946+ try {
947+ if(start != null && startColumns == null) {
948+ startColumns = createNonNullFieldSelector(start);
949+ }
950+ if(end != null && endColumns == null) {
951+ endColumns = createNonNullFieldSelector(end);
952+ }
953+ RowDef rowDef = checkRequest(session, rowDefId, start, startColumns, end, endColumns);
954+ rc = OperatorBasedRowCollector.newCollector(session,
955+ this,
956+ scanFlags,
957+ rowDef,
958+ indexId,
959+ columnBitMap,
960+ start,
961+ startColumns,
962+ end,
963+ endColumns,
964+ scanLimit);
965+ } finally {
966+ NEW_COLLECTOR_TAP.out();
967+ }
968+ return rc;
969+ }
970+
971+ @Override
972+ public void addSavedRowCollector(final Session session,
973+ final RowCollector rc) {
974+ final Integer tableId = rc.getTableId();
975+ final List<RowCollector> list = collectorsForTableId(session, tableId);
976+ if (!list.isEmpty()) {
977+ LOG.debug("Note: Nested RowCollector on tableId={} depth={}", tableId, list.size() + 1);
978+ assert list.get(list.size() - 1) != rc : "Redundant call";
979+ //
980+ // This disallows the patch because we agreed not to fix the
981+ // bug. However, these changes fix a memory leak, which is
982+ // important for robustness.
983+ //
984+ // throw new StoreException(122, "Bug 255 workaround is disabled");
985+ }
986+ list.add(rc);
987+ }
988+
989+ @Override
990+ public RowCollector getSavedRowCollector(final Session session,
991+ final int tableId) throws CursorIsUnknownException {
992+ final List<RowCollector> list = collectorsForTableId(session, tableId);
993+ if (list.isEmpty()) {
994+ LOG.debug("Nested RowCollector on tableId={} depth={}", tableId, (list.size() + 1));
995+ throw new CursorIsUnknownException(tableId);
996+ }
997+ return list.get(list.size() - 1);
998+ }
999+
1000+ @Override
1001+ public void removeSavedRowCollector(final Session session,
1002+ final RowCollector rc) throws CursorIsUnknownException {
1003+ final Integer tableId = rc.getTableId();
1004+ final List<RowCollector> list = collectorsForTableId(session, tableId);
1005+ if (list.isEmpty()) {
1006+ throw new CursorIsUnknownException (tableId);
1007+ }
1008+ final RowCollector removed = list.remove(list.size() - 1);
1009+ if (removed != rc) {
1010+ throw new CursorCloseBadException(tableId);
1011+ }
1012+ }
1013+
1014+ // This is to avoid circular dependencies in Guicer.
1015+ // TODO: There is still a functional circularity: store needs
1016+ // stats to clear them when deleting a group; stats need store to
1017+ // persist the stats. It would be better to separate out the
1018+ // higher level store functions from what other services require.
1019+ @Override
1020+ public void setIndexStatistics(IndexStatisticsService indexStatisticsService) {
1021+ this.indexStatisticsService = indexStatisticsService;
1022+ }
1023+
1024+ @Override
1025+ public TableStatistics getTableStatistics(final Session session, int tableId) {
1026+ final RowDef rowDef = getRowDef(session, tableId);
1027+ final TableStatistics ts = new TableStatistics(tableId);
1028+ final TableStatus status = rowDef.getTableStatus();
1029+ ts.setAutoIncrementValue(status.getAutoIncrement());
1030+ ts.setRowCount(status.getRowCount());
1031+ // TODO - get correct values
1032+ ts.setMeanRecordLength(100);
1033+ ts.setBlockSize(8192);
1034+ for(Index index : rowDef.getIndexes()) {
1035+ if(index.isSpatial()) {
1036+ continue;
1037+ }
1038+ TableStatistics.Histogram histogram = indexStatisticsToHistogram(session, index, createKey());
1039+ if(histogram != null) {
1040+ ts.addHistogram(histogram);
1041+ }
1042+ }
1043+ return ts;
1044+ }
1045+
1046+ @Override
1047+ public long getRowCount(Session session, boolean exact, RowData start, RowData end, byte[] columnBitMap) {
1048+ // TODO: Compute a reasonable value. The value 2 is special because it is not 0 or 1 but will
1049+ // still induce MySQL to use an index rather than a full table scan.
1050+ return 2;
1051+ }
1052+
1053+ @Override
1054+ public void dropGroup(final Session session, Group group) {
1055+ group.getRoot().traverseTableAndDescendants(new NopVisitor() {
1056+ @Override
1057+ public void visitUserTable(UserTable table) {
1058+ removeTrees(session, table);
1059+ }
1060+ });
1061+ }
1062+
1063+ @Override
1064+ public void truncateGroup(final Session session, final Group group) {
1065+ final List<Index> indexes = new ArrayList<>();
1066+ // Collect indexes, truncate table statuses
1067+ group.getRoot().traverseTableAndDescendants(new NopVisitor() {
1068+ @Override
1069+ public void visitUserTable(UserTable table) {
1070+ indexes.addAll(table.getIndexesIncludingInternal());
1071+ table.rowDef().getTableStatus().truncate();
1072+ }
1073+ });
1074+
1075+ indexes.addAll(group.getIndexes());
1076+ truncateIndexes(session, indexes);
1077+
1078+ // Truncate the group tree
1079+ truncateTree(session, group);
1080+ }
1081+
1082+ @Override
1083+ public void truncateTableStatus(final Session session, final int rowDefId) {
1084+ getRowDef(session, rowDefId).getTableStatus().truncate();
1085+ }
1086+
1087+ @Override
1088+ public void truncateIndexes(Session session, Collection<? extends Index> indexes) {
1089+ for(Index index : indexes) {
1090+ truncateTree(session, index.indexDef());
1091+ }
1092+ // Delete any statistics associated with index.
1093+ indexStatisticsService.deleteIndexStatistics(session, indexes);
1094+ }
1095+
1096+ @Override
1097+ public void deleteIndexes(final Session session, final Collection<? extends Index> indexes) {
1098+ for(Index index : indexes) {
1099+ final IndexDef indexDef = index.indexDef();
1100+ if(indexDef != null) {
1101+ removeTree(session, indexDef);
1102+ }
1103+ }
1104+ indexStatisticsService.deleteIndexStatistics(session, indexes);
1105+ }
1106+
1107+ @Override
1108+ public void removeTrees(Session session, UserTable table) {
1109+ // Table indexes
1110+ for(Index index : table.getIndexesIncludingInternal()) {
1111+ removeTree(session, index.indexDef());
1112+ }
1113+ indexStatisticsService.deleteIndexStatistics(session, table.getIndexesIncludingInternal());
1114+
1115+ // Group indexes
1116+ for(Index index : table.getGroupIndexes()) {
1117+ removeTree(session, index.indexDef());
1118+ }
1119+ indexStatisticsService.deleteIndexStatistics(session, table.getGroupIndexes());
1120+
1121+ // Sequence
1122+ if(table.getIdentityColumn() != null) {
1123+ deleteSequences(session, Collections.singleton(table.getIdentityColumn().getIdentityGenerator()));
1124+ }
1125+
1126+ // And the group tree
1127+ removeTree(session, table.getGroup());
1128+ }
1129+
1130+ @Override
1131+ public void removeTrees(Session session, Collection<? extends TreeLink> treeLinks) {
1132+ for(TreeLink link : treeLinks) {
1133+ removeTree(session, link);
1134+ }
1135+ }
1136+
1137+
1138+ //
1139+ // Internal
1140+ //
1141+
1142+ private List<RowCollector> collectorsForTableId(final Session session, final int tableId) {
1143+ List<RowCollector> list = session.get(COLLECTORS, tableId);
1144+ if (list == null) {
1145+ list = new ArrayList<>();
1146+ session.put(COLLECTORS, tableId, list);
1147+ }
1148+ return list;
1149+ }
1150+
1151+ private RowDef checkRequest(Session session, int rowDefId, RowData start, ColumnSelector startColumns,
1152+ RowData end, ColumnSelector endColumns) throws IllegalArgumentException {
1153+ if (start != null) {
1154+ if (startColumns == null) {
1155+ throw new IllegalArgumentException("non-null start row requires non-null ColumnSelector");
1156+ }
1157+ if( start.getRowDefId() != rowDefId) {
1158+ throw new IllegalArgumentException("Start and end RowData must specify the same rowDefId");
1159+ }
1160+ }
1161+ if (end != null) {
1162+ if (endColumns == null) {
1163+ throw new IllegalArgumentException("non-null end row requires non-null ColumnSelector");
1164+ }
1165+ if (end.getRowDefId() != rowDefId) {
1166+ throw new IllegalArgumentException("Start and end RowData must specify the same rowDefId");
1167+ }
1168+ }
1169+ final RowDef rowDef = getRowDef(session, rowDefId);
1170+ if (rowDef == null) {
1171+ throw new IllegalArgumentException("No RowDef for rowDefId " + rowDefId);
1172+ }
1173+ return rowDef;
1174+ }
1175+
1176+ private static ColumnSelector createNonNullFieldSelector(final RowData rowData) {
1177+ assert rowData != null;
1178+ return new ColumnSelector() {
1179+ @Override
1180+ public boolean includesColumn(int columnPosition) {
1181+ return !rowData.isNull(columnPosition);
1182+ }
1183+ };
1184+ }
1185+}
1186
1187=== modified file 'src/main/java/com/akiban/server/store/DelegatingStore.java'
1188--- src/main/java/com/akiban/server/store/DelegatingStore.java 2013-03-22 20:05:57 +0000
1189+++ src/main/java/com/akiban/server/store/DelegatingStore.java 2013-05-20 14:47:34 +0000
1190@@ -17,10 +17,14 @@
1191
1192 package com.akiban.server.store;
1193
1194+import com.akiban.ais.model.AkibanInformationSchema;
1195 import com.akiban.ais.model.Group;
1196 import com.akiban.ais.model.Index;
1197 import com.akiban.ais.model.Sequence;
1198-import com.akiban.ais.model.Table;
1199+import com.akiban.ais.model.TableName;
1200+import com.akiban.ais.model.UserTable;
1201+import com.akiban.qp.operator.StoreAdapter;
1202+import com.akiban.qp.rowtype.Schema;
1203 import com.akiban.server.rowdata.RowData;
1204 import com.akiban.server.rowdata.RowDef;
1205 import com.akiban.server.TableStatistics;
1206@@ -30,7 +34,8 @@
1207 import com.akiban.server.service.Service;
1208 import com.akiban.server.service.session.Session;
1209 import com.akiban.server.service.tree.TreeLink;
1210-import com.persistit.exception.PersistitException;
1211+import com.akiban.server.store.statistics.IndexStatisticsService;
1212+import com.persistit.Key;
1213
1214 import java.util.Collection;
1215
1216@@ -42,7 +47,8 @@
1217 this.delegate = delegate;
1218 }
1219
1220- protected S getDelegate() {
1221+ // TODO: Ditch DelegatingStore altogether
1222+ public S getDelegate() {
1223 return delegate;
1224 }
1225
1226@@ -62,11 +68,22 @@
1227 delegate.crash();
1228 }
1229
1230+ @Override
1231+ public AkibanInformationSchema getAIS(Session session) {
1232+ return delegate.getAIS(session);
1233+ }
1234+
1235+ @Override
1236 public RowDef getRowDef(Session session, int rowDefID) {
1237 return delegate.getRowDef(session, rowDefID);
1238 }
1239
1240 @Override
1241+ public RowDef getRowDef(Session session, TableName tableName) {
1242+ return delegate.getRowDef(session, tableName);
1243+ }
1244+
1245+ @Override
1246 public void startBulkLoad(Session session) {
1247 delegate.startBulkLoad(session);
1248 }
1249@@ -81,15 +98,15 @@
1250 delegate.finishBulkLoad(session);
1251 }
1252
1253- public void writeRow(Session session, RowData rowData) throws PersistitException {
1254+ public void writeRow(Session session, RowData rowData) {
1255 delegate.writeRow(session, rowData);
1256 }
1257
1258- public void deleteRow(Session session, RowData rowData, boolean deleteIndexes, boolean cascadeDelete) throws PersistitException {
1259+ public void deleteRow(Session session, RowData rowData, boolean deleteIndexes, boolean cascadeDelete) {
1260 delegate.deleteRow(session, rowData, deleteIndexes, cascadeDelete);
1261 }
1262
1263- public void updateRow(Session session, RowData oldRowData, RowData newRowData, ColumnSelector columnSelector, Index[] indexes) throws PersistitException {
1264+ public void updateRow(Session session, RowData oldRowData, RowData newRowData, ColumnSelector columnSelector, Index[] indexes) {
1265 delegate.updateRow(session, oldRowData, newRowData, columnSelector, indexes);
1266 }
1267
1268@@ -97,11 +114,11 @@
1269 delegate.dropGroup(session, group);
1270 }
1271
1272- public void truncateGroup(Session session, Group group) throws PersistitException {
1273+ public void truncateGroup(Session session, Group group) {
1274 delegate.truncateGroup(session, group);
1275 }
1276
1277- public void truncateTableStatus(Session session, int rowDefId) throws PersistitException {
1278+ public void truncateTableStatus(Session session, int rowDefId) {
1279 delegate.truncateTableStatus(session, rowDefId);
1280 }
1281
1282@@ -117,11 +134,6 @@
1283 delegate.removeSavedRowCollector(session, rc);
1284 }
1285
1286- @SuppressWarnings("deprecation")
1287- public RowCollector newRowCollector(Session session, int rowDefId, int indexId, int scanFlags, RowData start, RowData end, byte[] columnBitMap, ScanLimit scanLimit) {
1288- return delegate.newRowCollector(session, rowDefId, indexId, scanFlags, start, end, columnBitMap, scanLimit);
1289- }
1290-
1291 public RowCollector newRowCollector(Session session, int scanFlags, int rowDefId, int indexId, byte[] columnBitMap, RowData start, ColumnSelector startColumns, RowData end, ColumnSelector endColumns, ScanLimit scanLimit) {
1292 return delegate.newRowCollector(session, scanFlags, rowDefId, indexId, columnBitMap, start, startColumns, end, endColumns, scanLimit);
1293 }
1294@@ -134,10 +146,6 @@
1295 return delegate.getTableStatistics(session, tableId);
1296 }
1297
1298- public void flushIndexes(Session session) {
1299- delegate.flushIndexes(session);
1300- }
1301-
1302 public void buildIndexes(Session session, Collection<? extends Index> indexes, boolean defer) {
1303 delegate.buildIndexes(session, indexes, defer);
1304 }
1305@@ -146,22 +154,11 @@
1306 delegate.deleteIndexes(session, indexes);
1307 }
1308
1309- public void deleteSequences (Session session, Collection<? extends Sequence> sequences) {
1310- delegate.deleteSequences(session, sequences);
1311- }
1312-
1313- public void removeTrees(Session session, Table table) {
1314+ @Override
1315+ public void removeTrees(Session session, UserTable table) {
1316 delegate.removeTrees(session, table);
1317 }
1318
1319- public boolean isDeferIndexes() {
1320- return delegate.isDeferIndexes();
1321- }
1322-
1323- public void setDeferIndexes(boolean defer) {
1324- delegate.setDeferIndexes(defer);
1325- }
1326-
1327 @Override
1328 public void truncateIndexes(Session session, Collection<? extends Index> indexes) {
1329 delegate.truncateIndexes(session, indexes);
1330@@ -171,4 +168,34 @@
1331 public void removeTrees(Session session, Collection<? extends TreeLink> treeLinks) {
1332 delegate.removeTrees(session, treeLinks);
1333 }
1334+
1335+ @Override
1336+ public StoreAdapter createAdapter(Session session, Schema schema) {
1337+ return delegate.createAdapter(session, schema);
1338+ }
1339+
1340+ @Override
1341+ public void setIndexStatistics(IndexStatisticsService indexStatistics) {
1342+ delegate.setIndexStatistics(indexStatistics);
1343+ }
1344+
1345+ @Override
1346+ public void truncateTree(Session session, TreeLink treeLink) {
1347+ delegate.truncateTree(session, treeLink);
1348+ }
1349+
1350+ @Override
1351+ public Key createKey() {
1352+ return delegate.createKey();
1353+ }
1354+
1355+ @Override
1356+ public void deleteSequences(Session session, Collection<? extends Sequence> sequences) {
1357+ delegate.deleteSequences(session, sequences);
1358+ }
1359+
1360+ @Override
1361+ public void removeTree(Session session, TreeLink treeLink) {
1362+ delegate.removeTree(session, treeLink);
1363+ }
1364 }
1365
1366=== modified file 'src/main/java/com/akiban/server/store/PersistitStore.java'
1367--- src/main/java/com/akiban/server/store/PersistitStore.java 2013-05-03 00:59:49 +0000
1368+++ src/main/java/com/akiban/server/store/PersistitStore.java 2013-05-20 14:47:34 +0000
1369@@ -20,19 +20,18 @@
1370 import com.akiban.ais.model.*;
1371 import com.akiban.ais.model.Index.IndexType;
1372 import com.akiban.qp.operator.StoreAdapter;
1373-import com.akiban.qp.persistitadapter.OperatorBasedRowCollector;
1374 import com.akiban.qp.persistitadapter.PersistitAdapter;
1375 import com.akiban.qp.persistitadapter.PersistitHKey;
1376 import com.akiban.qp.persistitadapter.indexrow.PersistitIndexRow;
1377 import com.akiban.qp.persistitadapter.indexrow.PersistitIndexRowBuffer;
1378 import com.akiban.qp.rowtype.IndexRowType;
1379+import com.akiban.qp.rowtype.Schema;
1380 import com.akiban.qp.util.SchemaCache;
1381 import com.akiban.server.*;
1382 import com.akiban.server.api.dml.ColumnSelector;
1383 import com.akiban.server.api.dml.scan.LegacyRowWrapper;
1384 import com.akiban.server.api.dml.scan.NewRow;
1385 import com.akiban.server.api.dml.scan.NiceRow;
1386-import com.akiban.server.api.dml.scan.ScanLimit;
1387 import com.akiban.server.collation.CString;
1388 import com.akiban.server.collation.CStringKeyCoder;
1389 import com.akiban.server.error.*;
1390@@ -46,10 +45,6 @@
1391 import com.akiban.server.service.transaction.TransactionService;
1392 import com.akiban.server.service.tree.TreeLink;
1393 import com.akiban.server.service.tree.TreeService;
1394-import com.akiban.server.store.statistics.Histogram;
1395-import com.akiban.server.store.statistics.HistogramEntry;
1396-import com.akiban.server.store.statistics.IndexStatistics;
1397-import com.akiban.server.store.statistics.IndexStatisticsService;
1398 import com.akiban.util.tap.InOutTap;
1399 import com.akiban.util.tap.PointTap;
1400 import com.akiban.util.tap.Tap;
1401@@ -69,9 +64,8 @@
1402 import java.util.concurrent.atomic.AtomicLong;
1403 import java.util.concurrent.atomic.AtomicReference;
1404
1405-public class PersistitStore implements Store, Service {
1406-
1407- private static final Session.MapKey<Integer, List<RowCollector>> COLLECTORS = Session.MapKey.mapNamed("collectors");
1408+public class PersistitStore extends AbstractStore implements Service
1409+{
1410 private static final AtomicReference<Bulkload> activeBulkload = new AtomicReference<>();
1411
1412 private static final Logger LOG = LoggerFactory
1413@@ -85,8 +79,6 @@
1414
1415 private static final InOutTap TABLE_INDEX_MAINTENANCE_TAP = Tap.createTimer("index: maintain_table");
1416
1417- private static final InOutTap NEW_COLLECTOR_TAP = Tap.createTimer("read: new_collector");
1418-
1419 // an InOutTap would be nice, but pre-propagateDownGroup optimization, propagateDownGroup was called recursively
1420 // (via writeRow). PointTap handles this correctly, InOutTap does not, currently.
1421 private static final PointTap PROPAGATE_HKEY_CHANGE_TAP = Tap.createCount("write: propagate_hkey_change");
1422@@ -102,10 +94,6 @@
1423
1424 private final static int MAX_ROW_SIZE = 5000000;
1425
1426- private final static int MAX_INDEX_TRANCHE_SIZE = 10 * 1024 * 1024;
1427-
1428- private final static int KEY_STATE_SIZE_OVERHEAD = 50;
1429-
1430 private final static byte[] EMPTY_BYTE_ARRAY = new byte[0];
1431
1432 private boolean writeLockEnabled;
1433@@ -126,12 +114,6 @@
1434
1435 private DisplayFilter originalDisplayFilter;
1436
1437- private volatile IndexStatisticsService indexStatistics;
1438-
1439- private final Map<Tree, SortedSet<KeyState>> deferredIndexKeys = new HashMap<>();
1440-
1441- private int deferredIndexKeyLimit = MAX_INDEX_TRANCHE_SIZE;
1442-
1443 private FullTextIndexService fullTextService;
1444
1445 private RowDataValueCoder valueCoder;
1446@@ -161,6 +143,12 @@
1447 this.transactionService = transactionService;
1448 }
1449
1450+
1451+ //
1452+ // FullText change tracking
1453+ // TODO: Move out of PersistitStore
1454+ //
1455+
1456 public void setFullTextService(FullTextIndexService service)
1457 {
1458 fullTextService = service;
1459@@ -579,14 +567,15 @@
1460 }
1461
1462 @Override
1463+ public Key createKey() {
1464+ return treeService.createKey();
1465+ }
1466+
1467+ @Override
1468 public PersistitStore getPersistitStore() {
1469 return this;
1470 }
1471
1472- public TreeService treeService() {
1473- return treeService;
1474- }
1475-
1476 public Persistit getDb() {
1477 return treeService.getDb();
1478 }
1479@@ -603,11 +592,6 @@
1480 return treeService.getExchange(session, index.indexDef());
1481 }
1482
1483- public Key getKey()
1484- {
1485- return treeService.getKey();
1486- }
1487-
1488 public void releaseExchange(final Session session, final Exchange exchange) {
1489 treeService.releaseExchange(session, exchange);
1490 }
1491@@ -744,6 +728,7 @@
1492
1493 // --------------------- Implement Store interface --------------------
1494
1495+ @Override
1496 public AkibanInformationSchema getAIS(Session session) {
1497 Bulkload bulkload = activeBulkload.get();
1498 if (bulkload != null)
1499@@ -751,32 +736,18 @@
1500 return schemaManager.getAis(session);
1501 }
1502
1503- public RowDef getRowDef(Session session, TableName tableName) {
1504- Table table = getAIS(session).getTable(tableName);
1505- if(table == null) {
1506- throw new NoSuchTableException(tableName);
1507- }
1508- return table.rowDef();
1509- }
1510-
1511- @Override
1512- public RowDef getRowDef(Session session, int rowDefID) {
1513- Table table = getAIS(session).getUserTable(rowDefID);
1514- if(table == null) {
1515- throw new RowDefNotFoundException(rowDefID);
1516- }
1517- return table.rowDef();
1518- }
1519-
1520 @Override
1521 public void writeRow(Session session, RowData rowData)
1522- throws PersistitException
1523 {
1524 Bulkload bulkload = activeBulkload.get();
1525- if (bulkload != null)
1526- writeRowBulk(session, rowData, bulkload);
1527- else
1528- writeRowStandard(session, rowData, null, true);
1529+ try {
1530+ if (bulkload != null)
1531+ writeRowBulk(session, rowData, bulkload);
1532+ else
1533+ writeRowStandard(session, rowData, null, true);
1534+ } catch(PersistitException e) {
1535+ throw PersistitAdapter.wrapPersistitException(session, e);
1536+ }
1537 }
1538
1539 private void writeRowStandard(Session session,
1540@@ -804,7 +775,7 @@
1541 // in a good position to report a meaningful uniqueness violation, e.g. on the PK, since we don't have
1542 // the PK value handy. Instead, rely on PK validation when indexes are maintained.
1543
1544- packRowData(hEx, rowDef, rowData);
1545+ packRowData(hEx, rowData);
1546 // Store the h-row
1547 hEx.store();
1548 if (rowDef.isAutoIncrement()) {
1549@@ -824,7 +795,7 @@
1550 // bug1112940: Bump row count *after* uniqueness checks in insertIntoIndex
1551 rowDef.getTableStatus().rowsWritten(1);
1552
1553- if (propagateHKeyChanges && hasChildren(rowDef.userTable())) {
1554+ if (propagateHKeyChanges && rowDef.userTable().hasChildren()) {
1555 // The row being inserted might be the parent of orphan rows
1556 // already present. The hkeys of these
1557 // orphan rows need to be maintained. The hkeys of interest
1558@@ -860,17 +831,13 @@
1559 }
1560 propagateDownGroup(session, hEx, tablesRequiringHKeyMaintenance, indexRow, true, false);
1561 }
1562-
1563- if (deferredIndexKeyLimit <= 0) {
1564- putAllDeferredIndexKeys(session);
1565- }
1566 } finally {
1567 WRITE_ROW_TAP.out();
1568 releaseExchange(session, hEx);
1569 }
1570 }
1571
1572- private void writeRowBulk(Session session, RowData rowData, Bulkload bulkload) throws PersistitException {
1573+ private void writeRowBulk(Session session, RowData rowData, Bulkload bulkload) {
1574 final RowDef rowDef = writeRowCheck(session, rowData, true);
1575 if(session.get(StoreAdapter.STORE_ADAPTER_KEY) == null) {
1576 // Attaches itself to the session
1577@@ -908,25 +875,27 @@
1578 // Group table
1579 Key groupTableKey = bulkload.groupTableKey.get();
1580 Value groupTableValue = bulkload.groupTableValue.get();
1581- constructHKey(session, groupTableKey, rowDef, rowData, true, hiddenPk); // invokes key.clear()
1582- groupTableValue.clear();
1583- packRowData(groupTableValue, rowDef, rowData);
1584 try {
1585+ constructHKey(session, groupTableKey, rowDef, rowData, true, hiddenPk); // invokes key.clear()
1586+ groupTableValue.clear();
1587+ packRowData(groupTableValue, rowData);
1588 Tree tree = treeService.populateTreeCache(rowDef.getGroup()).getTree();
1589 bulkload.groupBuilder.treeBuilder.store(tree, groupTableKey, groupTableValue);
1590+
1591+ PersistitIndexRowBuffer indexRow = new PersistitIndexRowBuffer(adapter(session));
1592+ for (Index index : rowDef.getIndexes()) {
1593+ StorageAction action = index.isPrimaryKey() ? bulkload.pkStorage : bulkload.groupBuilder;
1594+ insertIntoIndex(session, index, rowData, groupTableKey, indexRow, deferIndexes, action);
1595+ }
1596 } catch (InvalidOperationException e) {
1597 throw e;
1598+ } catch (PersistitException e) {
1599+ throw PersistitAdapter.wrapPersistitException(session, e);
1600 } catch (Exception e) {
1601 LOG.error("while merging PKs", e);
1602 throw new BulkloadException("unknown exception (see log): " + e.getMessage());
1603 }
1604
1605- PersistitIndexRowBuffer indexRow = new PersistitIndexRowBuffer(adapter(session));
1606- for (Index index : rowDef.getIndexes()) {
1607- StorageAction action = index.isPrimaryKey() ? bulkload.pkStorage : bulkload.groupBuilder;
1608- insertIntoIndex(session, index, rowData, groupTableKey, indexRow, deferIndexes, action);
1609- }
1610-
1611 insertedRowsCount.incrementAndGet();
1612 }
1613
1614@@ -1030,18 +999,17 @@
1615 }
1616
1617 @Override
1618- public void deleteRow(Session session, RowData rowData, boolean deleteIndexes, boolean cascadeDelete) throws PersistitException
1619+ public void deleteRow(Session session, RowData rowData, boolean deleteIndexes, boolean cascadeDelete)
1620 {
1621 deleteRow(session, rowData, deleteIndexes, cascadeDelete, null, true);
1622 }
1623-
1624- private void deleteRow(Session session, RowData rowData, boolean deleteIndexes, boolean cascadeDelete,
1625+
1626+ private void deleteRow(Session session, RowData rowData, boolean deleteIndexes, boolean cascadeDelete,
1627 BitSet tablesRequiringHKeyMaintenance, boolean propagateHKeyChanges)
1628- throws PersistitException
1629 {
1630 RowDef rowDef = writeCheck(session, rowData, false);
1631 Exchange hEx = null;
1632-
1633+
1634 DELETE_ROW_TAP.in();
1635 try {
1636 hEx = getExchange(session, rowDef);
1637@@ -1075,9 +1043,11 @@
1638 // The row being deleted might be the parent of rows that
1639 // now become orphans. The hkeys
1640 // of these rows need to be maintained.
1641- if(propagateHKeyChanges && hasChildren(rowDef.userTable())) {
1642+ if(propagateHKeyChanges && rowDef.userTable().hasChildren()) {
1643 propagateDownGroup(session, hEx, tablesRequiringHKeyMaintenance, indexRow, deleteIndexes, cascadeDelete);
1644 }
1645+ } catch(PersistitException e) {
1646+ throw PersistitAdapter.wrapPersistitException(session, e);
1647 } finally {
1648 DELETE_ROW_TAP.out();
1649 releaseExchange(session, hEx);
1650@@ -1090,7 +1060,6 @@
1651 RowData newRowData,
1652 ColumnSelector columnSelector,
1653 Index[] indexes)
1654- throws PersistitException
1655 {
1656 updateRow(session, oldRowData, newRowData, columnSelector, indexes, (indexes != null), true);
1657 }
1658@@ -1102,7 +1071,6 @@
1659 Index[] indexesToMaintain,
1660 boolean indexesAsInsert,
1661 boolean propagateHKeyChanges)
1662- throws PersistitException
1663 {
1664 int rowDefId = oldRowData.getRowDefId();
1665 if (newRowData.getRowDefId() != rowDefId) {
1666@@ -1147,7 +1115,7 @@
1667 : null;
1668 if (tablesRequiringHKeyMaintenance == null) {
1669 // No PK or FK fields have changed. Just update the row.
1670- packRowData(hEx, newRowDef, mergedRowData);
1671+ packRowData(hEx, mergedRowData);
1672 // Store the h-row
1673 hEx.store();
1674 // Update the indexes (new row)
1675@@ -1169,58 +1137,14 @@
1676 deleteRow(session, oldRowData, true, false, tablesRequiringHKeyMaintenance, true);
1677 writeRowStandard(session, mergedRowData, tablesRequiringHKeyMaintenance, true); // May throw DuplicateKeyException
1678 }
1679+ } catch(PersistitException e) {
1680+ throw PersistitAdapter.wrapPersistitException(session, e);
1681 } finally {
1682 UPDATE_ROW_TAP.out();
1683 releaseExchange(session, hEx);
1684 }
1685 }
1686
1687- private BitSet analyzeFieldChanges(Session session, RowDef rowDef, RowData oldRow, RowData newRow)
1688- {
1689- BitSet tablesRequiringHKeyMaintenance;
1690- assert oldRow.getRowDefId() == newRow.getRowDefId();
1691- int fields = rowDef.getFieldCount();
1692- // Find the PK and FK fields
1693- BitSet keyField = new BitSet(fields);
1694- for (int pkFieldPosition : rowDef.getPKIndex().indexDef().getFields()) {
1695- keyField.set(pkFieldPosition, true);
1696- }
1697- for (int fkFieldPosition : rowDef.getParentJoinFields()) {
1698- keyField.set(fkFieldPosition, true);
1699- }
1700- // Find whether and where key fields differ
1701- boolean allEqual = true;
1702- for (int keyFieldPosition = keyField.nextSetBit(0);
1703- allEqual && keyFieldPosition >= 0;
1704- keyFieldPosition = keyField.nextSetBit(keyFieldPosition + 1)) {
1705- boolean fieldEqual = fieldEqual(rowDef, oldRow, newRow, keyFieldPosition);
1706- if (!fieldEqual) {
1707- allEqual = false;
1708- }
1709- }
1710- if (allEqual) {
1711- tablesRequiringHKeyMaintenance = null;
1712- } else {
1713- // A PK or FK field has changed, so the update has to be done as delete/insert. To minimize hkey
1714- // propagation work, find which tables (descendents of the updated table) are affected by hkey
1715- // changes.
1716- tablesRequiringHKeyMaintenance = hKeyDependentTableOrdinals(session, oldRow.getRowDefId());
1717- }
1718- return tablesRequiringHKeyMaintenance;
1719- }
1720-
1721- private BitSet hKeyDependentTableOrdinals(Session session, int rowDefId)
1722- {
1723- RowDef rowDef = getRowDef(session, rowDefId);
1724- UserTable table = rowDef.userTable();
1725- BitSet ordinals = new BitSet();
1726- for (UserTable hKeyDependentTable : table.hKeyDependentTables()) {
1727- int ordinal = hKeyDependentTable.rowDef().getOrdinal();
1728- ordinals.set(ordinal, true);
1729- }
1730- return ordinals;
1731- }
1732-
1733 private void checkNoGroupIndexes(Table table) {
1734 if (updateGroupIndexes && !table.getGroupIndexes().isEmpty()) {
1735 throw new UnsupportedOperationException("PersistitStore can't update group indexes; found on " + table);
1736@@ -1278,308 +1202,42 @@
1737 }
1738
1739 @Override
1740- public void dropGroup(Session session, Group group) {
1741- for(Table table : group.getRoot().getAIS().getUserTables().values()) {
1742- if(table.getGroup() == group) {
1743- removeTrees(session, table);
1744- }
1745- }
1746- // tableStatusCache entries updated elsewhere
1747- }
1748-
1749- @Override
1750- public void truncateGroup(final Session session, final Group group) throws PersistitException {
1751+ public void truncateGroup(final Session session, final Group group) {
1752 List<Index> indexes = new ArrayList<>();
1753- // Collect indexes, truncate table statuses
1754- for(UserTable table : group.getRoot().getAIS().getUserTables().values()) {
1755- if(table.getGroup() == group) {
1756- indexes.addAll(table.getIndexesIncludingInternal());
1757- table.rowDef().getTableStatus().truncate();
1758- }
1759- }
1760- indexes.addAll(group.getIndexes());
1761- truncateIndexes(session, indexes);
1762-
1763 // Truncate the group tree
1764 final Exchange hEx = getExchange(session, group);
1765- hEx.removeAll();
1766- releaseExchange(session, hEx);
1767- }
1768+ try {
1769+ // Collect indexes, truncate table statuses
1770+ for(UserTable table : group.getRoot().getAIS().getUserTables().values()) {
1771+ if(table.getGroup() == group) {
1772+ indexes.addAll(table.getIndexesIncludingInternal());
1773+ table.rowDef().getTableStatus().truncate();
1774+ }
1775+ }
1776+ indexes.addAll(group.getIndexes());
1777+ truncateIndexes(session, indexes);
1778
1779- // This is to avoid circular dependencies in Guicer.
1780- // TODO: There is still a functional circularity: store needs
1781- // stats to clear them when deleting a group; stats need store to
1782- // persist the stats. It would be better to separate out the
1783- // higher level store functions from what other services require.
1784- public void setIndexStatistics(IndexStatisticsService indexStatistics) {
1785- this.indexStatistics = indexStatistics;
1786+ hEx.removeAll();
1787+ } catch(PersistitException e) {
1788+ throw PersistitAdapter.wrapPersistitException(session, e);
1789+ } finally {
1790+ releaseExchange(session, hEx);
1791+ }
1792 }
1793
1794 @Override
1795 public void truncateIndexes(Session session, Collection<? extends Index> indexes) {
1796+ super.truncateIndexes(session, indexes);
1797 for(Index index : indexes) {
1798- Exchange iEx = getExchange(session, index);
1799- try {
1800- iEx.removeAll();
1801- if (index.isGroupIndex()) {
1802- new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.ROW_COUNT, iEx.getTree()).set(0);
1803- }
1804- } catch (PersistitException e) {
1805- throw new PersistitAdapterException(e);
1806- }
1807- releaseExchange(session, iEx);
1808- }
1809- // Delete any statistics associated with index.
1810- indexStatistics.deleteIndexStatistics(session, indexes);
1811- }
1812-
1813- @Override
1814- public void truncateTableStatus(final Session session, final int rowDefId) throws PersistitException {
1815- getRowDef(session, rowDefId).getTableStatus().truncate();
1816- }
1817-
1818- @Override
1819- public RowCollector getSavedRowCollector(final Session session,
1820- final int tableId) throws CursorIsUnknownException {
1821- final List<RowCollector> list = collectorsForTableId(session, tableId);
1822- if (list.isEmpty()) {
1823- LOG.debug("Nested RowCollector on tableId={} depth={}", tableId, (list.size() + 1));
1824- throw new CursorIsUnknownException(tableId);
1825- }
1826- return list.get(list.size() - 1);
1827- }
1828-
1829- @Override
1830- public void addSavedRowCollector(final Session session,
1831- final RowCollector rc) {
1832- final Integer tableId = rc.getTableId();
1833- final List<RowCollector> list = collectorsForTableId(session, tableId);
1834- if (!list.isEmpty()) {
1835- LOG.debug("Note: Nested RowCollector on tableId={} depth={}", tableId, list.size() + 1);
1836- assert list.get(list.size() - 1) != rc : "Redundant call";
1837- //
1838- // This disallows the patch because we agreed not to fix the
1839- // bug. However, these changes fix a memory leak, which is
1840- // important for robustness.
1841- //
1842- // throw new StoreException(122, "Bug 255 workaround is disabled");
1843- }
1844- list.add(rc);
1845- }
1846-
1847- @Override
1848- public void removeSavedRowCollector(final Session session,
1849- final RowCollector rc) throws CursorIsUnknownException {
1850- final Integer tableId = rc.getTableId();
1851- final List<RowCollector> list = collectorsForTableId(session, tableId);
1852- if (list.isEmpty()) {
1853- throw new CursorIsUnknownException (tableId);
1854- }
1855- final RowCollector removed = list.remove(list.size() - 1);
1856- if (removed != rc) {
1857- throw new CursorCloseBadException (tableId);
1858- }
1859- }
1860-
1861- private List<RowCollector> collectorsForTableId(final Session session,
1862- final int tableId) {
1863- List<RowCollector> list = session.get(COLLECTORS, tableId);
1864- if (list == null) {
1865- list = new ArrayList<>();
1866- session.put(COLLECTORS, tableId, list);
1867- }
1868- return list;
1869- }
1870-
1871- private RowDef checkRequest(Session session, int rowDefId, RowData start, ColumnSelector startColumns,
1872- RowData end, ColumnSelector endColumns) throws IllegalArgumentException {
1873- if (start != null) {
1874- if (startColumns == null) {
1875- throw new IllegalArgumentException("non-null start row requires non-null ColumnSelector");
1876- }
1877- if( start.getRowDefId() != rowDefId) {
1878- throw new IllegalArgumentException("Start and end RowData must specify the same rowDefId");
1879- }
1880- }
1881- if (end != null) {
1882- if (endColumns == null) {
1883- throw new IllegalArgumentException("non-null end row requires non-null ColumnSelector");
1884- }
1885- if (end.getRowDefId() != rowDefId) {
1886- throw new IllegalArgumentException("Start and end RowData must specify the same rowDefId");
1887- }
1888- }
1889- final RowDef rowDef = getRowDef(session, rowDefId);
1890- if (rowDef == null) {
1891- throw new IllegalArgumentException("No RowDef for rowDefId " + rowDefId);
1892- }
1893- return rowDef;
1894- }
1895-
1896- private static ColumnSelector createNonNullFieldSelector(final RowData rowData) {
1897- assert rowData != null;
1898- return new ColumnSelector() {
1899- @Override
1900- public boolean includesColumn(int columnPosition) {
1901- return !rowData.isNull(columnPosition);
1902- }
1903- };
1904- }
1905-
1906- @Override
1907- public RowCollector newRowCollector(Session session,
1908- int rowDefId,
1909- int indexId,
1910- int scanFlags,
1911- RowData start,
1912- RowData end,
1913- byte[] columnBitMap,
1914- ScanLimit scanLimit)
1915- {
1916- return newRowCollector(session, scanFlags, rowDefId, indexId, columnBitMap, start, null, end, null, scanLimit);
1917- }
1918-
1919- @Override
1920- public RowCollector newRowCollector(Session session,
1921- int scanFlags,
1922- int rowDefId,
1923- int indexId,
1924- byte[] columnBitMap,
1925- RowData start,
1926- ColumnSelector startColumns,
1927- RowData end,
1928- ColumnSelector endColumns,
1929- ScanLimit scanLimit)
1930- {
1931- NEW_COLLECTOR_TAP.in();
1932- RowCollector rc;
1933- try {
1934- if(start != null && startColumns == null) {
1935- startColumns = createNonNullFieldSelector(start);
1936- }
1937- if(end != null && endColumns == null) {
1938- endColumns = createNonNullFieldSelector(end);
1939- }
1940- RowDef rowDef = checkRequest(session, rowDefId, start, startColumns, end, endColumns);
1941- rc = OperatorBasedRowCollector.newCollector(config,
1942- session,
1943- this,
1944- scanFlags,
1945- rowDef,
1946- indexId,
1947- columnBitMap,
1948- start,
1949- startColumns,
1950- end,
1951- endColumns,
1952- scanLimit);
1953- } finally {
1954- NEW_COLLECTOR_TAP.out();
1955- }
1956- return rc;
1957- }
1958-
1959- public final static long HACKED_ROW_COUNT = 2;
1960-
1961- @Override
1962- public long getRowCount(final Session session, final boolean exact,
1963- final RowData start, final RowData end, final byte[] columnBitMap) {
1964- //
1965- // TODO: Compute a reasonable value. The value "2" is a hack -
1966- // special because it's not 0 or 1, but small enough to induce
1967- // MySQL to use an index rather than full table scan.
1968- //
1969- return HACKED_ROW_COUNT; // TODO: delete the HACKED_ROW_COUNT field when
1970- // this gets fixed
1971- // final int tableId = start.getRowDefId();
1972- // final TableStatus status = tableManager.getTableStatus(tableId);
1973- // return status.getRowCount();
1974- }
1975-
1976- @Override
1977- public TableStatistics getTableStatistics(final Session session, int tableId) {
1978- final RowDef rowDef = getRowDef(session, tableId);
1979- final TableStatistics ts = new TableStatistics(tableId);
1980- final TableStatus status = rowDef.getTableStatus();
1981- try {
1982- ts.setAutoIncrementValue(status.getAutoIncrement());
1983- ts.setRowCount(status.getRowCount());
1984- // TODO - get correct values
1985- ts.setMeanRecordLength(100);
1986- ts.setBlockSize(8192);
1987- } catch (PersistitException e) {
1988- throw new PersistitAdapterException(e);
1989- }
1990- for (Index index : rowDef.getIndexes()) {
1991- if (index.isSpatial())
1992- continue;
1993- TableStatistics.Histogram histogram = indexStatisticsToHistogram(session,
1994- index);
1995- if (histogram != null) {
1996- ts.addHistogram(histogram);
1997- }
1998- }
1999- return ts;
2000- }
2001-
2002- /** Convert from new-format histogram to old for adapter. */
2003- protected TableStatistics.Histogram indexStatisticsToHistogram(Session session,
2004- Index index) {
2005- IndexStatistics stats = indexStatistics.getIndexStatistics(session, index);
2006- if (stats == null) {
2007- return null;
2008- }
2009- Histogram fromHistogram = stats.getHistogram(0, index.getKeyColumns().size());
2010- if (fromHistogram == null) {
2011- return null;
2012- }
2013- IndexDef indexDef = index.indexDef();
2014- RowDef indexRowDef = indexDef.getRowDef();
2015- TableStatistics.Histogram toHistogram = new TableStatistics.Histogram(index.getIndexId());
2016- Key key = treeService.createKey();
2017- RowData indexRowData = new RowData(new byte[4096]);
2018- Object[] indexValues = new Object[indexRowDef.getFieldCount()];
2019- long count = 0;
2020- for (HistogramEntry entry : fromHistogram.getEntries()) {
2021- // Decode the key.
2022- int keylen = entry.getKeyBytes().length;
2023- System.arraycopy(entry.getKeyBytes(), 0, key.getEncodedBytes(), 0, keylen);
2024- key.setEncodedSize(keylen);
2025- key.indexTo(0);
2026- int depth = key.getDepth();
2027- // Copy key fields to index row.
2028- for (int field : indexDef.getFields()) {
2029- if (--depth >= 0) {
2030- indexValues[field] = key.decode();
2031- } else {
2032- indexValues[field] = null;
2033- }
2034- }
2035- indexRowData.createRow(indexRowDef, indexValues);
2036- // Partial counts to running total less than key.
2037- count += entry.getLessCount();
2038- toHistogram.addSample(new TableStatistics.HistogramSample(indexRowData.copy(),
2039- count));
2040- count += entry.getEqualCount();
2041- }
2042- // Add final entry with all nulls.
2043- Arrays.fill(indexValues, null);
2044- indexRowData.createRow(indexRowDef, indexValues);
2045- toHistogram.addSample(new TableStatistics.HistogramSample(indexRowData.copy(),
2046- count));
2047- return toHistogram;
2048- }
2049-
2050- boolean hasNullIndexSegments(RowData rowData, Index index)
2051- {
2052- IndexDef indexDef = index.indexDef();
2053- assert indexDef.getRowDef().getRowDefId() == rowData.getRowDefId();
2054- for (int i : indexDef.getFields()) {
2055- if (rowData.isNull(i)) {
2056- return true;
2057- }
2058- }
2059- return false;
2060+ if(index.isGroupIndex()) {
2061+ try {
2062+ Tree tree = index.indexDef().getTreeCache().getTree();
2063+ new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.ROW_COUNT, tree).set(0);
2064+ } catch(PersistitInterruptedException e) {
2065+ throw PersistitAdapter.wrapPersistitException(session, e);
2066+ }
2067+ }
2068+ }
2069 }
2070
2071 private void checkNotGroupIndex(Index index) {
2072@@ -1607,24 +1265,13 @@
2073 {
2074 checkNotGroupIndex(index);
2075 Exchange iEx = getExchange(session, index);
2076- constructIndexRow(iEx, rowData, index, hkey, indexRow, true);
2077- checkUniqueness(index, rowData, iEx);
2078- if (deferIndexes) {
2079- // TODO: bug767737, deferred indexing does not handle uniqueness
2080- synchronized (deferredIndexKeys) {
2081- SortedSet<KeyState> keySet = deferredIndexKeys.get(iEx.getTree());
2082- if (keySet == null) {
2083- keySet = new TreeSet<>();
2084- deferredIndexKeys.put(iEx.getTree(), keySet);
2085- }
2086- KeyState ks = new KeyState(iEx.getKey());
2087- keySet.add(ks);
2088- deferredIndexKeyLimit -= (ks.getBytes().length + KEY_STATE_SIZE_OVERHEAD);
2089- }
2090- } else {
2091+ try {
2092+ constructIndexRow(iEx, rowData, index, hkey, indexRow, true);
2093+ checkUniqueness(index, rowData, iEx);
2094 storageAction.store(iEx);
2095+ } finally {
2096+ releaseExchange(session, iEx);
2097 }
2098- releaseExchange(session, iEx);
2099 }
2100
2101 private void checkUniqueness(Index index, RowData rowData, Exchange iEx) throws PersistitException
2102@@ -1661,22 +1308,6 @@
2103 return keyExistsInIndex;
2104 }
2105
2106- private void putAllDeferredIndexKeys(final Session session) {
2107- synchronized (deferredIndexKeys) {
2108- for (final Map.Entry<Tree, SortedSet<KeyState>> entry : deferredIndexKeys
2109- .entrySet()) {
2110- final Exchange iEx = treeService.getExchange(session, entry.getKey());
2111- try {
2112- buildIndexAddKeys(entry.getValue(), iEx);
2113- entry.getValue().clear();
2114- } finally {
2115- treeService.releaseExchange(session, iEx);
2116- }
2117- }
2118- deferredIndexKeyLimit = MAX_INDEX_TRANCHE_SIZE;
2119- }
2120- }
2121-
2122 private void updateIndex(Session session,
2123 Index index,
2124 RowDef rowDef,
2125@@ -1761,47 +1392,11 @@
2126 releaseExchange(session, iEx);
2127 }
2128
2129- static boolean bytesEqual(byte[] a, int aoffset, int asize,
2130- byte[] b, int boffset, int bsize) {
2131- if (asize != bsize) {
2132- return false;
2133- }
2134- for (int i = 0; i < asize; i++) {
2135- if (a[i + aoffset] != b[i + boffset]) {
2136- return false;
2137- }
2138- }
2139- return true;
2140- }
2141-
2142- public static boolean fieldsEqual(RowDef rowDef, RowData a, RowData b, int[] fieldIndexes)
2143- {
2144- for (int fieldIndex : fieldIndexes) {
2145- long aloc = rowDef.fieldLocation(a, fieldIndex);
2146- long bloc = rowDef.fieldLocation(b, fieldIndex);
2147- if (!bytesEqual(a.getBytes(), (int) aloc, (int) (aloc >>> 32),
2148- b.getBytes(), (int) bloc, (int) (bloc >>> 32))) {
2149- return false;
2150- }
2151- }
2152- return true;
2153- }
2154-
2155- public static boolean fieldEqual(RowDef rowDef, RowData a, RowData b, int fieldPosition)
2156- {
2157- long aloc = rowDef.fieldLocation(a, fieldPosition);
2158- long bloc = rowDef.fieldLocation(b, fieldPosition);
2159- return bytesEqual(a.getBytes(), (int) aloc, (int) (aloc >>> 32),
2160- b.getBytes(), (int) bloc, (int) (bloc >>> 32));
2161- }
2162-
2163- public void packRowData(final Exchange hEx, final RowDef rowDef,
2164- final RowData rowData) {
2165- packRowData(hEx.getValue(), rowDef, rowData);
2166- }
2167-
2168- public void packRowData(final Value value, final RowDef rowDef,
2169- final RowData rowData) {
2170+ public void packRowData(final Exchange hEx,final RowData rowData) {
2171+ packRowData(hEx.getValue(), rowData);
2172+ }
2173+
2174+ public void packRowData(final Value value, final RowData rowData) {
2175 value.directPut(valueCoder, rowData, null);
2176 }
2177
2178@@ -1818,8 +1413,8 @@
2179 // rowData.prepareRow(0);
2180 }
2181
2182+ @Override
2183 public void buildIndexes(Session session, Collection<? extends Index> indexes, boolean defer) {
2184- flushIndexes(session);
2185 Set<Group> groups = new HashSet<>();
2186 Map<Integer,RowDef> userRowDefs = new HashMap<>();
2187 Set<Index> indexesToBuild = new HashSet<>();
2188@@ -1852,103 +1447,37 @@
2189 indexKeyCount++;
2190 }
2191 }
2192- if (deferredIndexKeyLimit <= 0) {
2193- putAllDeferredIndexKeys(session);
2194- }
2195 }
2196 }
2197 } catch (PersistitException e) {
2198 throw new PersistitAdapterException(e);
2199 }
2200- flushIndexes(session);
2201 LOG.debug("Inserted {} index keys into group {}", indexKeyCount, group.getName());
2202 }
2203 }
2204
2205 @Override
2206- public void removeTrees(Session session, Collection<? extends TreeLink> treeLinks) {
2207- try {
2208- for(TreeLink link : treeLinks) {
2209- if(!schemaManager.treeRemovalIsDelayed()) {
2210- Exchange ex = treeService.getExchange(session, link);
2211- ex.removeTree();
2212- // Do not releaseExchange, causes caching and leak for now unused tree
2213- }
2214- schemaManager.treeWasRemoved(session, link.getSchemaName(), link.getTreeName());
2215- }
2216- } catch (PersistitException e) {
2217- LOG.debug("Exception removing tree from Persistit", e);
2218- throw new PersistitAdapterException(e);
2219+ public void removeTrees(Session session, UserTable table) {
2220+ super.removeTrees(session, table);
2221+
2222+ // TODO: Generalize. Knowing about FullTextService is wrong.
2223+ for(FullTextIndex idx : table.getOwnFullTextIndexes()) {
2224+ fullTextService.dropIndex(session, idx);
2225 }
2226 }
2227
2228 @Override
2229- public void removeTrees(Session session, Table table) {
2230- Collection<TreeLink> treeLinks = new ArrayList<>();
2231-
2232- // delete all fulltext indexes
2233- if (table.isUserTable())
2234- {
2235- for (FullTextIndex idx : ((UserTable)table).getOwnFullTextIndexes())
2236- fullTextService.dropIndex(session, idx);
2237- }
2238-
2239- // Add all index trees
2240- final Collection<TableIndex> tableIndexes = table.isUserTable() ? ((UserTable)table).getIndexesIncludingInternal() : table.getIndexes();
2241- final Collection<GroupIndex> groupIndexes = table.getGroupIndexes();
2242- for(Index index : tableIndexes) {
2243- treeLinks.add(index.indexDef());
2244- }
2245- for(Index index : groupIndexes) {
2246- treeLinks.add(index.indexDef());
2247- }
2248- // Drop the sequence trees too.
2249- if (table.isUserTable() && ((UserTable)table).getIdentityColumn() != null) {
2250- treeLinks.add(((UserTable)table).getIdentityColumn().getIdentityGenerator());
2251- } else if (table.isGroupTable()) {
2252- for (UserTable userTable : table.getAIS().getUserTables().values()) {
2253- if (userTable.getGroup() == table.getGroup() &&
2254- userTable.getIdentityColumn() != null) {
2255- treeLinks.add(userTable.getIdentityColumn().getIdentityGenerator());
2256- }
2257- }
2258- }
2259-
2260- // And the group tree
2261- treeLinks.add(table.getGroup());
2262- // And drop them all
2263- removeTrees(session, treeLinks);
2264- indexStatistics.deleteIndexStatistics(session, tableIndexes);
2265- indexStatistics.deleteIndexStatistics(session, groupIndexes);
2266- }
2267-
2268- public void flushIndexes(final Session session) {
2269- try {
2270- putAllDeferredIndexKeys(session);
2271- } catch (PersistitAdapterException e) {
2272- LOG.debug("Exception while trying to flush deferred index keys", e);
2273- throw e;
2274- }
2275- }
2276-
2277 public void deleteIndexes(final Session session, final Collection<? extends Index> indexes) {
2278- List<TreeLink> links = new ArrayList<>(indexes.size());
2279+ super.deleteIndexes(session, indexes);
2280+ // TODO: Generalize. Knowing about FullTextService is wrong.
2281 for(Index index : indexes) {
2282 // no trees to drop
2283 if (index.getIndexType() == IndexType.FULL_TEXT)
2284 {
2285 fullTextService.dropIndex(session, (FullTextIndex)index);
2286 indexes.remove(index);
2287- continue;
2288- }
2289- final IndexDef indexDef = index.indexDef();
2290- if(indexDef == null) {
2291- throw new IllegalStateException("indexDef is null for index: " + index);
2292- }
2293- links.add(indexDef);
2294+ }
2295 }
2296- removeTrees(session, links);
2297- indexStatistics.deleteIndexStatistics(session, indexes);
2298 }
2299
2300 @Override
2301@@ -1956,28 +1485,6 @@
2302 removeTrees(session, sequences);
2303 }
2304
2305- private void buildIndexAddKeys(final SortedSet<KeyState> keys,
2306- final Exchange iEx) {
2307- final long start = System.nanoTime();
2308- try {
2309- for (final KeyState keyState : keys) {
2310- keyState.copyTo(iEx.getKey());
2311- iEx.store();
2312- }
2313- } catch (PersistitException e) {
2314- LOG.error(e.getMessage());
2315- throw new PersistitAdapterException(e);
2316- }
2317- final long elapsed = System.nanoTime() - start;
2318- if (LOG.isInfoEnabled()) {
2319- LOG.debug("Index builder inserted {} keys into index tree {} in {} seconds", new Object[]{
2320- keys.size(),
2321- iEx.getTree().getName(),
2322- elapsed / 1000000000
2323- });
2324- }
2325- }
2326-
2327 private RowData mergeRows(RowDef rowDef, RowData currentRow, RowData newRowData, ColumnSelector columnSelector) {
2328 NewRow mergedRow = NiceRow.fromRowData(currentRow, rowDef);
2329 NewRow newRow = new LegacyRowWrapper(rowDef, newRowData);
2330@@ -1990,24 +1497,6 @@
2331 return mergedRow.toRowData();
2332 }
2333
2334- private RowDef rowDefFromExplicitOrId(Session session, RowData rowData) {
2335- RowDef rowDef = rowData.getExplicitRowDef();
2336- if(rowDef == null) {
2337- rowDef = getRowDef(session, rowData.getRowDefId());
2338- }
2339- return rowDef;
2340- }
2341-
2342- @Override
2343- public boolean isDeferIndexes() {
2344- return deferIndexes;
2345- }
2346-
2347- @Override
2348- public void setDeferIndexes(final boolean defer) {
2349- deferIndexes = defer;
2350- }
2351-
2352 private void lockAndCheckVersion(Session session, RowDef rowDef) {
2353 final LockService.Mode mode = LockService.Mode.SHARED;
2354 final int tableID = rowDef.getRowDefId();
2355@@ -2070,24 +1559,11 @@
2356 return visitor;
2357 }
2358
2359- public TableStatus getTableStatus(Table table) {
2360- TableStatus ts = null;
2361- if(table.rowDef() != null) {
2362- ts = table.rowDef().getTableStatus();
2363- }
2364- return ts;
2365- }
2366-
2367 private static PersistitAdapter adapter(Session session)
2368 {
2369 return (PersistitAdapter) session.get(StoreAdapter.STORE_ADAPTER_KEY);
2370 }
2371
2372- private static boolean hasChildren(UserTable table) {
2373- // At runtime, getCandidateChildJoins() = getChildJoins() and doesn't involve building a temp list
2374- return !table.getCandidateChildJoins().isEmpty();
2375- }
2376-
2377 private TreeBuilder createTreeBuilder(String name, float bufferBoolFraction) {
2378 TreeBuilder tb = new TreeBuilder(getDb(), name, -1, bufferBoolFraction)
2379 // TODO: throw an Akiban dup-key exception once we can handle them
2380@@ -2153,6 +1629,38 @@
2381 lockKeyAppender.clear();
2382 }
2383
2384+ @Override
2385+ public StoreAdapter createAdapter(Session session, Schema schema) {
2386+ return new PersistitAdapter(schema, this, treeService, session, config);
2387+ }
2388+
2389+ @Override
2390+ public void truncateTree(Session session, TreeLink treeLink) {
2391+ Exchange iEx = treeService.getExchange(session, treeLink);
2392+ try {
2393+ iEx.removeAll();
2394+ } catch (PersistitException e) {
2395+ throw PersistitAdapter.wrapPersistitException(session, e);
2396+ } finally {
2397+ releaseExchange(session, iEx);
2398+ }
2399+ }
2400+
2401+ @Override
2402+ public void removeTree(Session session, TreeLink treeLink) {
2403+ try {
2404+ if(!schemaManager.treeRemovalIsDelayed()) {
2405+ Exchange ex = treeService.getExchange(session, treeLink);
2406+ ex.removeTree();
2407+ // Do not releaseExchange, causes caching and leak for now unused tree
2408+ }
2409+ schemaManager.treeWasRemoved(session, treeLink.getSchemaName(), treeLink.getTreeName());
2410+ } catch (PersistitException e) {
2411+ LOG.debug("Exception removing tree from Persistit", e);
2412+ throw PersistitAdapter.wrapPersistitException(session, e);
2413+ }
2414+ }
2415+
2416 private class Bulkload {
2417
2418 Bulkload(final Persistit persistit, AkibanInformationSchema ais) {
2419
2420=== modified file 'src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java'
2421--- src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java 2013-04-11 18:35:20 +0000
2422+++ src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java 2013-05-20 14:47:34 +0000
2423@@ -474,11 +474,7 @@
2424 for(ChangedTableDescription desc : alteredTables) {
2425 if(desc.isNewGroup()) {
2426 UserTable oldTable = oldAIS.getUserTable(desc.getOldName());
2427- try {
2428- oldTable.rowDef().getTableStatus().setOrdinal(0);
2429- } catch(PersistitException e) {
2430- throw wrapPersistitException(session, e);
2431- }
2432+ oldTable.rowDef().getTableStatus().setOrdinal(0);
2433 }
2434 }
2435
2436
2437=== modified file 'src/main/java/com/akiban/server/store/Store.java'
2438--- src/main/java/com/akiban/server/store/Store.java 2013-04-14 00:26:23 +0000
2439+++ src/main/java/com/akiban/server/store/Store.java 2013-05-20 14:47:34 +0000
2440@@ -17,57 +17,40 @@
2441
2442 package com.akiban.server.store;
2443
2444+import com.akiban.ais.model.AkibanInformationSchema;
2445 import com.akiban.ais.model.Group;
2446 import com.akiban.ais.model.Index;
2447 import com.akiban.ais.model.Sequence;
2448-import com.akiban.ais.model.Table;
2449+import com.akiban.ais.model.TableName;
2450+import com.akiban.ais.model.UserTable;
2451+import com.akiban.qp.operator.StoreAdapter;
2452+import com.akiban.qp.rowtype.Schema;
2453 import com.akiban.server.TableStatistics;
2454 import com.akiban.server.api.dml.ColumnSelector;
2455 import com.akiban.server.api.dml.scan.ScanLimit;
2456 import com.akiban.server.rowdata.RowData;
2457 import com.akiban.server.rowdata.RowDef;
2458 import com.akiban.server.service.session.Session;
2459+import com.akiban.server.service.tree.KeyCreator;
2460 import com.akiban.server.service.tree.TreeLink;
2461-import com.persistit.exception.PersistitException;
2462-import com.persistit.exception.RollbackException;
2463+import com.akiban.server.store.statistics.IndexStatisticsService;
2464
2465 import java.util.Collection;
2466
2467-/**
2468- * An abstraction for a layer that stores and retrieves data
2469- *
2470- * @author peter
2471- *
2472- */
2473-public interface Store {
2474+public interface Store extends KeyCreator {
2475
2476 /** Get the RowDef for the given ID. Note, a transaction should be active before calling this. */
2477 RowDef getRowDef(Session session, int rowDefID);
2478-
2479- void writeRow(Session session, RowData rowData) throws PersistitException;
2480-
2481- void deleteRow(Session session, RowData rowData, boolean deleteIndexes, boolean cascadeDelete) throws PersistitException;
2482+ RowDef getRowDef(Session session, TableName tableName);
2483+ AkibanInformationSchema getAIS(Session session);
2484+
2485+ void writeRow(Session session, RowData rowData);
2486+
2487+ void deleteRow(Session session, RowData rowData, boolean deleteIndexes, boolean cascadeDelete);
2488
2489 void updateRow(Session session, RowData oldRowData,
2490 RowData newRowData,
2491- ColumnSelector columnSelector, Index[] indexes) throws PersistitException;
2492-
2493- /**
2494- * See {@link #newRowCollector(Session, int, int, int, byte[], RowData, ColumnSelector, RowData, ColumnSelector, ScanLimit)}
2495- * for parameter descriptions.
2496- * @throws Exception
2497- *
2498- * @deprecated This constructor is ambiguous and may not return the expected rows. Fields from <code>start</code>
2499- * and <code>end</code> that are <code>NULL</code> are considered to be <b>unset</b>.
2500- */
2501- RowCollector newRowCollector(Session session,
2502- int rowDefId,
2503- int indexId,
2504- int scanFlags,
2505- RowData start,
2506- RowData end,
2507- byte[] columnBitMap,
2508- ScanLimit scanLimit);
2509+ ColumnSelector columnSelector, Index[] indexes);
2510
2511 /**
2512 * Create a new RowCollector.
2513@@ -134,13 +117,10 @@
2514 * Truncate the given group. This includes indexes from all tables, group
2515 * indexes, the group itself, and all table statuses.
2516 */
2517- void truncateGroup(Session session, Group group) throws PersistitException;
2518-
2519- void truncateTableStatus(Session session, int rowDefId) throws RollbackException, PersistitException;
2520-
2521- boolean isDeferIndexes();
2522- void setDeferIndexes(boolean b);
2523- void flushIndexes(Session session);
2524+ void truncateGroup(Session session, Group group);
2525+
2526+ void truncateTableStatus(Session session, int rowDefId);
2527+
2528 void deleteIndexes(Session session, Collection<? extends Index> indexes);
2529 void buildIndexes(Session session, Collection<? extends Index> indexes, boolean deferIndexes);
2530
2531@@ -149,10 +129,11 @@
2532 * Remove all trees, and their contents, associated with the given table.
2533 * @param session Session
2534 * @param table Table
2535- * @throws PersistitException
2536- * @throws Exception
2537+ * @throws Exception
2538 */
2539- void removeTrees(Session session, Table table);
2540+ void removeTrees(Session session, UserTable table);
2541+ void removeTree(Session session, TreeLink treeLink);
2542+ void truncateTree(Session session, TreeLink treeLink);
2543
2544 /**
2545 * Low level operation. Removes the given trees and <i>only</i> the given trees.
2546@@ -171,4 +152,8 @@
2547 void finishBulkLoad(Session session);
2548
2549 boolean isBulkloading();
2550+
2551+ void setIndexStatistics(IndexStatisticsService indexStatistics);
2552+
2553+ StoreAdapter createAdapter(Session session, Schema schema);
2554 }
2555
2556=== modified file 'src/main/java/com/akiban/server/store/statistics/IndexStatisticsServiceImpl.java'
2557--- src/main/java/com/akiban/server/store/statistics/IndexStatisticsServiceImpl.java 2013-04-11 05:51:16 +0000
2558+++ src/main/java/com/akiban/server/store/statistics/IndexStatisticsServiceImpl.java 2013-05-20 14:47:34 +0000
2559@@ -146,7 +146,7 @@
2560 if (table.hasMemoryTableFactory()) {
2561 return table.getMemoryTableFactory().rowCount();
2562 } else {
2563- return store.getTableStatus(table).getRowCount();
2564+ return table.rowDef().getTableStatus().getRowCount();
2565 }
2566 }
2567 final Exchange ex = store.getExchange(session, index);
2568@@ -161,7 +161,7 @@
2569 @Override
2570 public long countEntriesApproximate(Session session, Index index) {
2571 if (index.isTableIndex()) {
2572- return store.getTableStatus(((TableIndex)index).getTable()).getApproximateRowCount();
2573+ return index.leafMostTable().rowDef().getTableStatus().getApproximateRowCount();
2574 }
2575 final Exchange ex = store.getExchange(session, index);
2576 try {
2577
2578=== modified file 'src/main/java/com/akiban/server/store/statistics/PersistitStoreIndexStatistics.java'
2579--- src/main/java/com/akiban/server/store/statistics/PersistitStoreIndexStatistics.java 2013-03-22 20:05:57 +0000
2580+++ src/main/java/com/akiban/server/store/statistics/PersistitStoreIndexStatistics.java 2013-05-20 14:47:34 +0000
2581@@ -284,6 +284,9 @@
2582 RowData rowData = new RowData(new byte[INITIAL_ROW_SIZE]);
2583 RowDef indexStatisticsRowDef = getIndexStatsRowDef(session);
2584 RowDef indexStatisticsEntryRowDef = getIndexStatsEntryRowDef(session);
2585+ if(index.indexDef() == null) {
2586+ return;
2587+ }
2588 int tableId = index.indexDef().getRowDef().getRowDefId();
2589 int indexId = index.getIndexId();
2590 // Delete index_statistics_entry rows.
2591
2592=== modified file 'src/test/java/com/akiban/server/test/it/keyupdate/FixCountStarIT.java'
2593--- src/test/java/com/akiban/server/test/it/keyupdate/FixCountStarIT.java 2013-04-11 05:51:16 +0000
2594+++ src/test/java/com/akiban/server/test/it/keyupdate/FixCountStarIT.java 2013-05-20 14:47:34 +0000
2595@@ -95,7 +95,7 @@
2596 public void run() {
2597 if (index.isTableIndex()) {
2598 TableIndex tIndex = (TableIndex) index;
2599- store().getPersistitStore().getTableStatus(tIndex.getTable()).setRowCount(newVal);
2600+ tIndex.leafMostTable().rowDef().getTableStatus().setRowCount(newVal);
2601 }
2602 else {
2603 PersistitStore store = store().getPersistitStore();
2604
2605=== modified file 'src/test/java/com/akiban/server/test/it/rowtests/ObjectToKeyIT.java'
2606--- src/test/java/com/akiban/server/test/it/rowtests/ObjectToKeyIT.java 2013-03-22 20:05:57 +0000
2607+++ src/test/java/com/akiban/server/test/it/rowtests/ObjectToKeyIT.java 2013-05-20 14:47:34 +0000
2608@@ -38,7 +38,7 @@
2609 }
2610
2611 private void testObjectToKey(FieldDef field, Object... testValues) throws PersistitException {
2612- Key key = persistitStore().getKey();
2613+ Key key = persistitStore().createKey();
2614 PersistitKeyAppender appender = PersistitKeyAppender.create(key);
2615 for(Object inObj : testValues) {
2616 key.clear();
2617
2618=== modified file 'src/test/java/com/akiban/server/test/it/store/AbstractScanBase.java'
2619--- src/test/java/com/akiban/server/test/it/store/AbstractScanBase.java 2013-03-27 04:42:10 +0000
2620+++ src/test/java/com/akiban/server/test/it/store/AbstractScanBase.java 2013-05-20 14:47:34 +0000
2621@@ -139,8 +139,8 @@
2622 final byte[] columnBitMap, final int indexId) throws Exception {
2623 int scanCount = 0;
2624 result.clear();
2625- final RowCollector rc = store().newRowCollector(session(), rowDefId, indexId,
2626- scanFlags, start, end, columnBitMap, null);
2627+ final RowCollector rc = store().newRowCollector(session(), scanFlags, rowDefId, indexId, columnBitMap,
2628+ start, null, end, null, null);
2629 if (VERBOSE) {
2630 System.out.println("Test " + test);
2631 }

Subscribers

People subscribed via source and target branches