Merge lp:~nwilliams/akiban-server/seq-accum-fix into lp:~akiban-technologies/akiban-server/trunk
- seq-accum-fix
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Nathan Williams |
Approved revision: | 2631 |
Merged at revision: | 2619 |
Proposed branch: | lp:~nwilliams/akiban-server/seq-accum-fix |
Merge into: | lp:~akiban-technologies/akiban-server/trunk |
Diff against target: |
1154 lines (+472/-163) 28 files modified
pom.xml (+1/-1) src/main/java/com/akiban/ais/model/AISMerge.java (+12/-8) src/main/java/com/akiban/ais/model/Column.java (+12/-7) src/main/java/com/akiban/ais/model/Index.java (+3/-4) src/main/java/com/akiban/ais/model/Sequence.java (+45/-39) src/main/java/com/akiban/ais/model/aisb2/AISBBasedBuilder.java (+1/-1) src/main/java/com/akiban/ais/util/TableChangeValidator.java (+1/-0) src/main/java/com/akiban/qp/persistitadapter/OperatorStoreGIHandler.java (+2/-2) src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java (+2/-2) src/main/java/com/akiban/qp/persistitadapter/indexrow/PersistitIndexRowBuffer.java (+1/-1) src/main/java/com/akiban/server/AccumulatorAdapter.java (+33/-30) src/main/java/com/akiban/server/MemoryOnlyTableStatusCache.java (+0/-7) src/main/java/com/akiban/server/PersistitAccumulatorTableStatusCache.java (+7/-22) src/main/java/com/akiban/server/TableStatus.java (+0/-2) src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java (+1/-2) src/main/java/com/akiban/server/store/PersistitStore.java (+8/-2) src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java (+27/-22) src/main/java/com/akiban/server/store/SequenceFixUpRoutines.java (+139/-0) src/main/java/com/akiban/server/store/statistics/IndexStatisticsServiceImpl.java (+2/-2) src/main/java/com/akiban/sql/aisddl/TableDDL.java (+3/-4) src/test/java/com/akiban/server/rowdata/SchemaFactory.java (+2/-1) src/test/java/com/akiban/server/test/it/dxl/AlterTableBasicIT.java (+19/-0) src/test/java/com/akiban/server/test/it/keyupdate/FixCountStarIT.java (+1/-1) src/test/java/com/akiban/sql/aisddl/SequenceDDLIT.java (+53/-1) src/test/java/com/akiban/sql/aisddl/TableDDLIT.java (+1/-1) src/test/java/com/akiban/sql/pg/PostgresServerMiscYamlIT.java (+8/-1) src/test/resources/com/akiban/sql/pg/yaml/functional/test-seq-fixup-routines.yaml (+40/-0) src/test/resources/com/akiban/sql/pg/yaml/functional/test-sequence.yaml (+48/-0) |
To merge this branch: | bzr merge lp:~nwilliams/akiban-server/seq-accum-fix |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Mike McMahon | Needs Information | ||
Akiban Build User | Needs Fixing | ||
Thomas Jones-Low | Approve | ||
Review via email: mp+158279@code.launchpad.net |
Commit message
Description of the change
Fix bugs related to sequence value handling.
This addresses all issues outlined in bug1167045 by changing the underlying sequence accumulator to SEQ and providing routines for manual upgrade paths.
Also take the strict approach to using Persistit 3.2.9 so there is a tiny amount of noise. Look at all but the last 2 commits to avoid it. As Peter mentioned in his proposal, AccumInfo and AccumulatorAdapter could use a refactor pass but this doesn't do that.
Diff ordered summary, ignoring 3.2.9 noise, below.
AISMerge/
Turns out there was another subtle bug in sequence tree usage. If you dropped an sequence and recreated one with the same name, you would pick the tree back up because the tree name handling was being skipped. Go through the whole AISMerge flow to fix this.
Sequence
The interesting part of the change. Switch to SEQ for the accumulator type and always update by 1 (as is now exposed). Simpler over all and next/current share common code now.
AISBasedBuilder
Sequences created through the builder had a user specified initial value but unconditionally Long.MIN for the min. Use init for min for consistency (cycle is always false).
TableChangeVali
Detect if the incoming table had an identity generation change. Will be useful when we hook up the ALTER, but just serves the new routine right now.
PSSM
Remove now dead code and create routines on start-up (see below).
SequenceFixUpRo
Two routines for fixing existing databases, seq_tree_reset and seq_identity_
TableDDL
Change SERIAL alias from BY DEFAULT to ALWAYS.
PostgresServerM
The seq_tree_reset routine requires the global lock enabled for extra-safety. Turn it on for this IT only so it can be tested in yaml.
AlterTableBasic
Extended existing tests, added new for identified bugs and new functionality.
Akiban Build User (build-akiban) wrote : | # |
There were 2 failures during build/test:
* job server-build failed at build number 3954: http://
* view must-pass failed: server-build is red
Nathan Williams (nwilliams) wrote : | # |
Thanks for the review Thomas. Persistit side isn't quite in yet.
Mike McMahon (mmcm) wrote : | # |
How do we want to do backups? The answer doesn't have to be that today's DDL works, but akdump needs to do something. For instance, could we create the new table with bare BIGINT NOT NULL and then ALTER with GENERATED ALWAYS AS IDENTITY (START WITH) after loading data?
Nathan Williams (nwilliams) wrote : | # |
That is probably the simplest. Should be just a tiny parser tweak to get hat ALTER accepted I think.
Postgres is similar. For SERIAL columns, they create the table as is, create and attach sequence, restore value with a routine, and then do the table inserts. They don't do IDENTITY so the BY DEFAULT vs ALWAYS isn't an issue. If you insert values manually into them, it will get a duplicate key when the sequence comes to it.
Peter Beaman (pbeaman) wrote : | # |
All good. I looked closely at the new logic in the Sequence method; other
changes look plausible but I'm not familiar enough with AIS building and
merging to be sure. I believe the Persistit branch is now also good to go.
On Thu, Apr 11, 2013 at 11:07 AM, Nathan Williams <email address hidden>wrote:
> That is probably the simplest. Should be just a tiny parser tweak to get
> hat ALTER accepted I think.
>
> Postgres is similar. For SERIAL columns, they create the table as is,
> create and attach sequence, restore value with a routine, and then do the
> table inserts. They don't do IDENTITY so the BY DEFAULT vs ALWAYS isn't an
> issue. If you insert values manually into them, it will get a duplicate key
> when the sequence comes to it.
> --
>
> https:/
> Your team Akiban Technologies is subscribed to branch lp:akiban-server.
>
Nathan Williams (nwilliams) wrote : | # |
Mike, did you want dump support incorporated into this branch or can we do that separately?
Mike McMahon (mmcm) wrote : | # |
Let's do it separately. I have the parser about ready to go. It was 90% of the way there, but a LOOKAHEAD wasn't broad enough.
Preview Diff
1 | === modified file 'pom.xml' | |||
2 | --- pom.xml 2013-04-05 15:56:11 +0000 | |||
3 | +++ pom.xml 2013-04-11 06:17:20 +0000 | |||
4 | @@ -100,7 +100,7 @@ | |||
5 | 100 | <dependency> | 100 | <dependency> |
6 | 101 | <groupId>com.akiban</groupId> | 101 | <groupId>com.akiban</groupId> |
7 | 102 | <artifactId>akiban-persistit</artifactId> | 102 | <artifactId>akiban-persistit</artifactId> |
9 | 103 | <version>3.2.8-SNAPSHOT</version> | 103 | <version>3.2.9-SNAPSHOT</version> |
10 | 104 | </dependency> | 104 | </dependency> |
11 | 105 | <dependency> | 105 | <dependency> |
12 | 106 | <groupId>com.akiban</groupId> | 106 | <groupId>com.akiban</groupId> |
13 | 107 | 107 | ||
14 | === modified file 'src/main/java/com/akiban/ais/model/AISMerge.java' | |||
15 | --- src/main/java/com/akiban/ais/model/AISMerge.java 2013-04-02 05:00:56 +0000 | |||
16 | +++ src/main/java/com/akiban/ais/model/AISMerge.java 2013-04-11 06:17:20 +0000 | |||
17 | @@ -55,7 +55,7 @@ | |||
18 | 55 | * frozen. If you pass a frozen AIS into the merge, the copy process unfreeze the copy. | 55 | * frozen. If you pass a frozen AIS into the merge, the copy process unfreeze the copy. |
19 | 56 | */ | 56 | */ |
20 | 57 | public class AISMerge { | 57 | public class AISMerge { |
22 | 58 | public enum MergeType { ADD_TABLE, MODIFY_TABLE, ADD_INDEX } | 58 | public enum MergeType { ADD_TABLE, MODIFY_TABLE, ADD_INDEX, OTHER } |
23 | 59 | 59 | ||
24 | 60 | private static class JoinChange { | 60 | private static class JoinChange { |
25 | 61 | public final Join join; | 61 | public final Join join; |
26 | @@ -121,6 +121,10 @@ | |||
27 | 121 | return new AISMerge(generator, copyAISForAdd(sourceAIS), null, MergeType.ADD_INDEX, null, null); | 121 | return new AISMerge(generator, copyAISForAdd(sourceAIS), null, MergeType.ADD_INDEX, null, null); |
28 | 122 | } | 122 | } |
29 | 123 | 123 | ||
30 | 124 | public static AISMerge newForOther(NameGenerator generator, AkibanInformationSchema sourceAIS) { | ||
31 | 125 | return new AISMerge(generator, copyAISForAdd(sourceAIS), null, MergeType.OTHER, null, null); | ||
32 | 126 | } | ||
33 | 127 | |||
34 | 124 | private AISMerge(NameGenerator nameGenerator, AkibanInformationSchema targetAIS, UserTable sourceTable, | 128 | private AISMerge(NameGenerator nameGenerator, AkibanInformationSchema targetAIS, UserTable sourceTable, |
35 | 125 | MergeType mergeType, List<JoinChange> changedJoins, Map<IndexName,IndexInfo> indexesToFix) { | 129 | MergeType mergeType, List<JoinChange> changedJoins, Map<IndexName,IndexInfo> indexesToFix) { |
36 | 126 | this.nameGenerator = nameGenerator; | 130 | this.nameGenerator = nameGenerator; |
37 | @@ -644,14 +648,14 @@ | |||
38 | 644 | newAIS.addView(newView); | 648 | newAIS.addView(newView); |
39 | 645 | } | 649 | } |
40 | 646 | 650 | ||
43 | 647 | public static AkibanInformationSchema mergeSequence (AkibanInformationSchema oldAIS, | 651 | public AkibanInformationSchema mergeSequence(Sequence sequence) |
42 | 648 | Sequence sequence) | ||
44 | 649 | { | 652 | { |
50 | 650 | AkibanInformationSchema newAIS = copyAISForAdd(oldAIS); | 653 | Sequence newSeq = Sequence.create(targetAIS, sequence); |
51 | 651 | newAIS.addSequence(sequence); | 654 | newSeq.setTreeName(nameGenerator.generateSequenceTreeName(newSeq)); |
52 | 652 | newAIS.validate(AISValidations.LIVE_AIS_VALIDATIONS).throwIfNecessary(); | 655 | targetAIS.addSequence(newSeq); |
53 | 653 | newAIS.freeze(); | 656 | targetAIS.validate(AISValidations.LIVE_AIS_VALIDATIONS).throwIfNecessary(); |
54 | 654 | return newAIS; | 657 | targetAIS.freeze(); |
55 | 658 | return targetAIS; | ||
56 | 655 | } | 659 | } |
57 | 656 | 660 | ||
58 | 657 | public static AkibanInformationSchema mergeRoutine(AkibanInformationSchema oldAIS, | 661 | public static AkibanInformationSchema mergeRoutine(AkibanInformationSchema oldAIS, |
59 | 658 | 662 | ||
60 | === modified file 'src/main/java/com/akiban/ais/model/Column.java' | |||
61 | --- src/main/java/com/akiban/ais/model/Column.java 2013-03-26 20:26:45 +0000 | |||
62 | +++ src/main/java/com/akiban/ais/model/Column.java 2013-04-11 06:17:20 +0000 | |||
63 | @@ -274,15 +274,20 @@ | |||
64 | 274 | } | 274 | } |
65 | 275 | 275 | ||
66 | 276 | /** | 276 | /** |
73 | 277 | * This is a three state boolean: | 277 | * <p> |
74 | 278 | * True: column created with GENERATED BY DEFAULT AS IDENTITY | 278 | * This is a three state boolean: |
75 | 279 | * False: Column created with GENERATED ALWAYS AS IDENTITY | 279 | * <ul> |
76 | 280 | * Null: Not generated by identity column | 280 | * <li><b>True</b>: column created with GENERATED BY DEFAULT AS IDENTITY</li> |
77 | 281 | * | 281 | * <li><b>False</b>: Column created with GENERATED ALWAYS AS IDENTITY</li> |
78 | 282 | * NOTE: It is possible for the GetInitialAutoIncrement to be | 282 | * <li><b>null</b>: Not generated by identity column</li> |
79 | 283 | * </ul> | ||
80 | 284 | * </p> | ||
81 | 285 | * <p> | ||
82 | 286 | * <b>NOTE</b>: It is possible for the GetInitialAutoIncrement to be | ||
83 | 283 | * not null and this to be null, as MySQL generated tables use | 287 | * not null and this to be null, as MySQL generated tables use |
84 | 284 | * auto-increment value, where as the Akiban SQL use the | 288 | * auto-increment value, where as the Akiban SQL use the |
86 | 285 | * identity generators. | 289 | * identity generators. |
87 | 290 | * </p> | ||
88 | 286 | */ | 291 | */ |
89 | 287 | public final Boolean getDefaultIdentity() { | 292 | public final Boolean getDefaultIdentity() { |
90 | 288 | return defaultIdentity; | 293 | return defaultIdentity; |
91 | 289 | 294 | ||
92 | === modified file 'src/main/java/com/akiban/ais/model/Index.java' | |||
93 | --- src/main/java/com/akiban/ais/model/Index.java 2013-03-22 20:05:57 +0000 | |||
94 | +++ src/main/java/com/akiban/ais/model/Index.java 2013-04-11 06:17:20 +0000 | |||
95 | @@ -359,12 +359,11 @@ | |||
96 | 359 | 359 | ||
97 | 360 | // Unique, non-PK indexes store a "null separator value", making index rows unique that would otherwise | 360 | // Unique, non-PK indexes store a "null separator value", making index rows unique that would otherwise |
98 | 361 | // be considered duplicates due to nulls. | 361 | // be considered duplicates due to nulls. |
100 | 362 | public long nextNullSeparatorValue(TreeService treeService) | 362 | public long nextNullSeparatorValue() |
101 | 363 | { | 363 | { |
102 | 364 | Tree tree = indexDef.getTreeCache().getTree(); | 364 | Tree tree = indexDef.getTreeCache().getTree(); |
106 | 365 | AccumulatorAdapter accumulator = | 365 | AccumulatorAdapter accumulator = new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.UNIQUE_ID, tree); |
107 | 366 | new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.UNIQUE_ID, treeService, tree); | 366 | return accumulator.seqAllocate(); |
105 | 367 | return accumulator.updateAndGet(1); | ||
108 | 368 | } | 367 | } |
109 | 369 | 368 | ||
110 | 370 | // akTypes, akCollators and tInstances provide type info for physical index rows. | 369 | // akTypes, akCollators and tInstances provide type info for physical index rows. |
111 | 371 | 370 | ||
112 | === modified file 'src/main/java/com/akiban/ais/model/Sequence.java' | |||
113 | --- src/main/java/com/akiban/ais/model/Sequence.java 2013-03-22 20:05:57 +0000 | |||
114 | +++ src/main/java/com/akiban/ais/model/Sequence.java 2013-04-11 06:17:20 +0000 | |||
115 | @@ -42,7 +42,13 @@ | |||
116 | 42 | ais.addSequence(sequence); | 42 | ais.addSequence(sequence); |
117 | 43 | return sequence; | 43 | return sequence; |
118 | 44 | } | 44 | } |
120 | 45 | 45 | ||
121 | 46 | /** Create a copy of <code>seq</code>. Internal data (e.g. tree name) is not copied. */ | ||
122 | 47 | public static Sequence create (AkibanInformationSchema ais, Sequence seq) { | ||
123 | 48 | return create(ais, seq.sequenceName.getSchemaName(), seq.sequenceName.getTableName(), | ||
124 | 49 | seq.startsWith, seq.increment, seq.minValue, seq.maxValue, seq.cycle); | ||
125 | 50 | } | ||
126 | 51 | |||
127 | 46 | protected Sequence (AkibanInformationSchema ais, | 52 | protected Sequence (AkibanInformationSchema ais, |
128 | 47 | String schemaName, | 53 | String schemaName, |
129 | 48 | String sequenceName, | 54 | String sequenceName, |
130 | @@ -55,13 +61,14 @@ | |||
131 | 55 | AISInvariants.checkNullName(schemaName, "Sequence", "schema name"); | 61 | AISInvariants.checkNullName(schemaName, "Sequence", "schema name"); |
132 | 56 | AISInvariants.checkNullName(sequenceName, "Sequence", "table name"); | 62 | AISInvariants.checkNullName(sequenceName, "Sequence", "table name"); |
133 | 57 | AISInvariants.checkDuplicateSequence(ais, schemaName, sequenceName); | 63 | AISInvariants.checkDuplicateSequence(ais, schemaName, sequenceName); |
135 | 58 | 64 | ||
136 | 59 | this.sequenceName = new TableName (schemaName, sequenceName); | 65 | this.sequenceName = new TableName (schemaName, sequenceName); |
137 | 60 | this.startsWith = start; | 66 | this.startsWith = start; |
138 | 61 | this.increment = increment; | 67 | this.increment = increment; |
139 | 62 | this.minValue = minValue; | 68 | this.minValue = minValue; |
140 | 63 | this.maxValue = maxValue; | 69 | this.maxValue = maxValue; |
141 | 64 | this.cycle = cycle; | 70 | this.cycle = cycle; |
142 | 71 | this.range = maxValue - minValue + 1; | ||
143 | 65 | } | 72 | } |
144 | 66 | 73 | ||
145 | 67 | public final TableName getSequenceName() { | 74 | public final TableName getSequenceName() { |
146 | @@ -108,6 +115,7 @@ | |||
147 | 108 | private final long maxValue; | 115 | private final long maxValue; |
148 | 109 | private final boolean cycle; | 116 | private final boolean cycle; |
149 | 110 | 117 | ||
150 | 118 | private final long range; | ||
151 | 111 | private AtomicReference<TreeCache> treeCache = new AtomicReference<>(); | 119 | private AtomicReference<TreeCache> treeCache = new AtomicReference<>(); |
152 | 112 | 120 | ||
153 | 113 | 121 | ||
154 | @@ -126,44 +134,42 @@ | |||
155 | 126 | public TreeCache getTreeCache() { | 134 | public TreeCache getTreeCache() { |
156 | 127 | return treeCache.get(); | 135 | return treeCache.get(); |
157 | 128 | } | 136 | } |
170 | 129 | 137 | ||
171 | 130 | public long nextValue(TreeService treeService) throws PersistitException { | 138 | public long nextValue() throws PersistitException { |
172 | 131 | 139 | // Note: Ever increasing, always incremented by 1, rollbacks will leave gaps. See bug1167045 for discussion. | |
173 | 132 | Tree tree = getTreeCache().getTree(); | 140 | AccumulatorAdapter accum = getAdapter(); |
174 | 133 | AccumulatorAdapter accum = new AccumulatorAdapter (AccumInfo.AUTO_INC, treeService, tree); | 141 | long rawSequence = accum.seqAllocate(); |
175 | 134 | long value = accum.updateAndGet(increment); | 142 | |
176 | 135 | 143 | long nextValue = notCycled(rawSequence); | |
177 | 136 | if (value > maxValue && increment > 0) { | 144 | if (nextValue > maxValue || nextValue < minValue) { |
178 | 137 | if (cycle) { | 145 | if(!cycle) { |
167 | 138 | value = minValue; | ||
168 | 139 | accum.set(value); | ||
169 | 140 | } else { | ||
179 | 141 | throw new SequenceLimitExceededException(this); | 146 | throw new SequenceLimitExceededException(this); |
180 | 142 | } | 147 | } |
206 | 143 | } else if (value < minValue && increment < 0) { | 148 | nextValue = cycled(nextValue); |
207 | 144 | if (cycle) { | 149 | } |
208 | 145 | value = maxValue; | 150 | return nextValue; |
209 | 146 | accum.set(value); | 151 | } |
210 | 147 | } else { | 152 | |
211 | 148 | throw new SequenceLimitExceededException (this); | 153 | public long currentValue() throws PersistitException { |
212 | 149 | } | 154 | AccumulatorAdapter accum = getAdapter(); |
213 | 150 | } | 155 | return cycled(notCycled(accum.getSnapshot())); |
214 | 151 | return value; | 156 | } |
215 | 152 | } | 157 | |
216 | 153 | 158 | private AccumulatorAdapter getAdapter() throws PersistitException { | |
217 | 154 | public long currentValue(TreeService treeService) throws PersistitException { | 159 | Tree tree = getTreeCache().getTree(); |
218 | 155 | Tree tree = getTreeCache().getTree(); | 160 | return new AccumulatorAdapter(AccumInfo.SEQUENCE, tree); |
219 | 156 | AccumulatorAdapter accum = new AccumulatorAdapter (AccumInfo.AUTO_INC, treeService, tree); | 161 | } |
220 | 157 | return accum.getSnapshot(AccumInfo.AUTO_INC, treeService, tree); | 162 | |
221 | 158 | } | 163 | private long notCycled(long rawSequence) { |
222 | 159 | 164 | // -1 so first is startsWith, second is startsWith+inc, etc | |
223 | 160 | public void setStartWithAccumulator(TreeService treeService) throws PersistitException { | 165 | return startsWith + ((rawSequence - 1) * increment); |
224 | 161 | Tree tree = getTreeCache().getTree(); | 166 | } |
225 | 162 | AccumulatorAdapter accum = new AccumulatorAdapter (AccumInfo.AUTO_INC, treeService, tree); | 167 | |
226 | 163 | // Set the starting value to startsWith - increment, | 168 | private long cycled(long notCycled) { |
227 | 164 | // which will be, on first call to nextValue() be updated to the start value | 169 | long mod = (notCycled - minValue) % range; |
228 | 165 | // TODO: This can cause problems if startsWith is within increment of | 170 | if(mod < 0) { |
229 | 166 | // Long.MaxValue or Long.MinValue. | 171 | mod += range; |
230 | 167 | accum.set(startsWith - increment); | 172 | } |
231 | 173 | return minValue + mod; | ||
232 | 168 | } | 174 | } |
233 | 169 | } | 175 | } |
234 | 170 | 176 | ||
235 | === modified file 'src/main/java/com/akiban/ais/model/aisb2/AISBBasedBuilder.java' | |||
236 | --- src/main/java/com/akiban/ais/model/aisb2/AISBBasedBuilder.java 2013-04-01 18:36:36 +0000 | |||
237 | +++ src/main/java/com/akiban/ais/model/aisb2/AISBBasedBuilder.java 2013-04-11 06:17:20 +0000 | |||
238 | @@ -234,7 +234,7 @@ | |||
239 | 234 | String sequenceName = "temp-seq-" + userTable + "-" + name; | 234 | String sequenceName = "temp-seq-" + userTable + "-" + name; |
240 | 235 | long initValue = initialAutoInc.longValue(); | 235 | long initValue = initialAutoInc.longValue(); |
241 | 236 | aisb.sequence(schema, sequenceName, | 236 | aisb.sequence(schema, sequenceName, |
243 | 237 | initValue, 1L, Long.MIN_VALUE, Long.MAX_VALUE, | 237 | initValue, 1L, initValue, Long.MAX_VALUE, |
244 | 238 | false); | 238 | false); |
245 | 239 | aisb.columnAsIdentity(schema, userTable, name, sequenceName, true); | 239 | aisb.columnAsIdentity(schema, userTable, name, sequenceName, true); |
246 | 240 | aisb.akibanInformationSchema(). | 240 | aisb.akibanInformationSchema(). |
247 | 241 | 241 | ||
248 | === modified file 'src/main/java/com/akiban/ais/util/TableChangeValidator.java' | |||
249 | --- src/main/java/com/akiban/ais/util/TableChangeValidator.java 2013-03-22 20:05:57 +0000 | |||
250 | +++ src/main/java/com/akiban/ais/util/TableChangeValidator.java 2013-04-11 06:17:20 +0000 | |||
251 | @@ -563,6 +563,7 @@ | |||
252 | 563 | if((oldNull != newNull) || | 563 | if((oldNull != newNull) || |
253 | 564 | !oldCol.getName().equals(newCol.getName()) || | 564 | !oldCol.getName().equals(newCol.getName()) || |
254 | 565 | !Objects.equal(oldCol.getDefaultValue(), newCol.getDefaultValue()) || | 565 | !Objects.equal(oldCol.getDefaultValue(), newCol.getDefaultValue()) || |
255 | 566 | !Objects.equal(oldCol.getDefaultIdentity(), newCol.getDefaultIdentity()) || | ||
256 | 566 | sequenceChanged(oldCol.getIdentityGenerator(), newCol.getIdentityGenerator())) { | 567 | sequenceChanged(oldCol.getIdentityGenerator(), newCol.getIdentityGenerator())) { |
257 | 567 | return ChangeLevel.METADATA; | 568 | return ChangeLevel.METADATA; |
258 | 568 | } | 569 | } |
259 | 569 | 570 | ||
260 | === modified file 'src/main/java/com/akiban/qp/persistitadapter/OperatorStoreGIHandler.java' | |||
261 | --- src/main/java/com/akiban/qp/persistitadapter/OperatorStoreGIHandler.java 2013-03-22 20:05:57 +0000 | |||
262 | +++ src/main/java/com/akiban/qp/persistitadapter/OperatorStoreGIHandler.java 2013-04-11 06:17:20 +0000 | |||
263 | @@ -115,7 +115,7 @@ | |||
264 | 115 | private void storeExchange(GroupIndex groupIndex, Exchange exchange) { | 115 | private void storeExchange(GroupIndex groupIndex, Exchange exchange) { |
265 | 116 | try { | 116 | try { |
266 | 117 | exchange.store(); | 117 | exchange.store(); |
268 | 118 | AccumulatorAdapter.updateAndGet(AccumulatorAdapter.AccumInfo.ROW_COUNT, exchange, 1); | 118 | AccumulatorAdapter.sumAdd(AccumulatorAdapter.AccumInfo.ROW_COUNT, exchange, 1); |
269 | 119 | } catch (PersistitException e) { | 119 | } catch (PersistitException e) { |
270 | 120 | throw new PersistitAdapterException(e); | 120 | throw new PersistitAdapterException(e); |
271 | 121 | } | 121 | } |
272 | @@ -127,7 +127,7 @@ | |||
273 | 127 | private void removeExchange(GroupIndex groupIndex, Exchange exchange) { | 127 | private void removeExchange(GroupIndex groupIndex, Exchange exchange) { |
274 | 128 | try { | 128 | try { |
275 | 129 | if (exchange.remove()) { | 129 | if (exchange.remove()) { |
277 | 130 | AccumulatorAdapter.updateAndGet(AccumulatorAdapter.AccumInfo.ROW_COUNT, exchange, -1); | 130 | AccumulatorAdapter.sumAdd(AccumulatorAdapter.AccumInfo.ROW_COUNT, exchange, -1); |
278 | 131 | } | 131 | } |
279 | 132 | else | 132 | else |
280 | 133 | UNNEEDED_DELETE_TAP.hit(); | 133 | UNNEEDED_DELETE_TAP.hit(); |
281 | 134 | 134 | ||
282 | === modified file 'src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java' | |||
283 | --- src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java 2013-03-22 20:05:57 +0000 | |||
284 | +++ src/main/java/com/akiban/qp/persistitadapter/PersistitAdapter.java 2013-04-11 06:17:20 +0000 | |||
285 | @@ -447,9 +447,9 @@ | |||
286 | 447 | private long sequenceValue (Sequence sequence, boolean getCurrentValue) { | 447 | private long sequenceValue (Sequence sequence, boolean getCurrentValue) { |
287 | 448 | try { | 448 | try { |
288 | 449 | if (getCurrentValue) { | 449 | if (getCurrentValue) { |
290 | 450 | return sequence.currentValue(treeService); | 450 | return sequence.currentValue(); |
291 | 451 | } else { | 451 | } else { |
293 | 452 | return sequence.nextValue(treeService); | 452 | return sequence.nextValue(); |
294 | 453 | } | 453 | } |
295 | 454 | } catch (PersistitException e) { | 454 | } catch (PersistitException e) { |
296 | 455 | rollbackIfNeeded(e); | 455 | rollbackIfNeeded(e); |
297 | 456 | 456 | ||
298 | === modified file 'src/main/java/com/akiban/qp/persistitadapter/indexrow/PersistitIndexRowBuffer.java' | |||
299 | --- src/main/java/com/akiban/qp/persistitadapter/indexrow/PersistitIndexRowBuffer.java 2013-03-22 20:05:57 +0000 | |||
300 | +++ src/main/java/com/akiban/qp/persistitadapter/indexrow/PersistitIndexRowBuffer.java 2013-04-11 06:17:20 +0000 | |||
301 | @@ -201,7 +201,7 @@ | |||
302 | 201 | hasNull = pKey.isNull(); | 201 | hasNull = pKey.isNull(); |
303 | 202 | } | 202 | } |
304 | 203 | if (hasNull) { | 203 | if (hasNull) { |
306 | 204 | nullSeparator = index.nextNullSeparatorValue(adapter.persistit().treeService()); | 204 | nullSeparator = index.nextNullSeparatorValue(); |
307 | 205 | } | 205 | } |
308 | 206 | } | 206 | } |
309 | 207 | // else: We're creating an index row to update or delete. Don't need a new null separator value. | 207 | // else: We're creating an index row to update or delete. Don't need a new null separator value. |
310 | 208 | 208 | ||
311 | === modified file 'src/main/java/com/akiban/server/AccumulatorAdapter.java' | |||
312 | --- src/main/java/com/akiban/server/AccumulatorAdapter.java 2013-03-22 20:05:57 +0000 | |||
313 | +++ src/main/java/com/akiban/server/AccumulatorAdapter.java 2013-04-11 06:17:20 +0000 | |||
314 | @@ -18,41 +18,41 @@ | |||
315 | 18 | package com.akiban.server; | 18 | package com.akiban.server; |
316 | 19 | 19 | ||
317 | 20 | import com.akiban.server.error.PersistitAdapterException; | 20 | import com.akiban.server.error.PersistitAdapterException; |
318 | 21 | import com.akiban.server.service.tree.TreeService; | ||
319 | 22 | import com.persistit.Accumulator; | 21 | import com.persistit.Accumulator; |
320 | 23 | import com.persistit.Exchange; | 22 | import com.persistit.Exchange; |
321 | 24 | import com.persistit.Transaction; | ||
322 | 25 | import com.persistit.Tree; | 23 | import com.persistit.Tree; |
323 | 26 | import com.persistit.exception.PersistitException; | 24 | import com.persistit.exception.PersistitException; |
324 | 27 | import com.persistit.exception.PersistitInterruptedException; | 25 | import com.persistit.exception.PersistitInterruptedException; |
325 | 28 | 26 | ||
326 | 29 | public class AccumulatorAdapter { | 27 | public class AccumulatorAdapter { |
327 | 30 | 28 | ||
331 | 31 | public static long getSnapshot(AccumInfo accumInfo, TreeService treeService, Tree tree) | 29 | public static long getSnapshot(AccumInfo accumInfo, Tree tree) throws PersistitInterruptedException { |
329 | 32 | throws PersistitInterruptedException | ||
330 | 33 | { | ||
332 | 34 | Accumulator accumulator = getAccumulator(accumInfo, tree); | 30 | Accumulator accumulator = getAccumulator(accumInfo, tree); |
335 | 35 | Transaction txn = getCurrentTrx(treeService); | 31 | return accumulator.getSnapshotValue(); |
334 | 36 | return accumulator.getSnapshotValue(txn); | ||
336 | 37 | } | 32 | } |
337 | 38 | 33 | ||
341 | 39 | public static long updateAndGet(AccumInfo accumInfo, Exchange exchange, long value) { | 34 | public static void sumAdd(AccumInfo accumInfo, Exchange exchange, long value) { |
342 | 40 | Accumulator accumulator = getAccumulator(accumInfo, exchange.getTree()); | 35 | Accumulator.SumAccumulator sum = (Accumulator.SumAccumulator)getAccumulator(accumInfo, exchange.getTree()); |
343 | 41 | return accumulator.update(value, exchange.getTransaction()); | 36 | sum.add(value); |
344 | 42 | } | 37 | } |
345 | 43 | 38 | ||
348 | 44 | public static long getLiveValue(AccumInfo accumInfo, TreeService treeService, Tree tree) | 39 | public static long getLiveValue(AccumInfo accumInfo, Tree tree) { |
347 | 45 | { | ||
349 | 46 | Accumulator accumulator = getAccumulator(accumInfo, tree); | 40 | Accumulator accumulator = getAccumulator(accumInfo, tree); |
350 | 47 | return accumulator.getLiveValue(); | 41 | return accumulator.getLiveValue(); |
351 | 48 | } | 42 | } |
352 | 49 | 43 | ||
353 | 50 | public long getSnapshot() throws PersistitInterruptedException { | 44 | public long getSnapshot() throws PersistitInterruptedException { |
359 | 51 | return accumulator.getSnapshotValue(getCurrentTrx()); | 45 | return accumulator.getSnapshotValue(); |
360 | 52 | } | 46 | } |
361 | 53 | 47 | ||
362 | 54 | public long updateAndGet(long value) { | 48 | public void sumAdd(long value) { |
363 | 55 | return accumulator.update(value, getCurrentTrx()); | 49 | Accumulator.SumAccumulator sum = (Accumulator.SumAccumulator)accumulator; |
364 | 50 | sum.add(value); | ||
365 | 51 | } | ||
366 | 52 | |||
367 | 53 | public long seqAllocate() { | ||
368 | 54 | Accumulator.SeqAccumulator seq = (Accumulator.SeqAccumulator)accumulator; | ||
369 | 55 | return seq.allocate(); | ||
370 | 56 | } | 56 | } |
371 | 57 | 57 | ||
372 | 58 | public long getLiveValue() { | 58 | public long getLiveValue() { |
373 | @@ -67,32 +67,29 @@ | |||
374 | 67 | long current = getSnapshot(); | 67 | long current = getSnapshot(); |
375 | 68 | if(evenIfLess || value > current) { | 68 | if(evenIfLess || value > current) { |
376 | 69 | long diff = value - current; | 69 | long diff = value - current; |
378 | 70 | this.updateAndGet(diff); | 70 | this.sumAdd(diff); |
379 | 71 | } | 71 | } |
380 | 72 | } | 72 | } |
381 | 73 | 73 | ||
384 | 74 | public AccumulatorAdapter(AccumInfo accumInfo, TreeService treeService, Tree tree) { | 74 | public AccumulatorAdapter(AccumInfo accumInfo, Tree tree) { |
383 | 75 | this.treeService = treeService; | ||
385 | 76 | this.accumulator = getAccumulator(accumInfo, tree); | 75 | this.accumulator = getAccumulator(accumInfo, tree); |
386 | 77 | } | 76 | } |
387 | 78 | 77 | ||
388 | 79 | private static Accumulator getAccumulator(AccumInfo accumInfo, Tree tree) { | 78 | private static Accumulator getAccumulator(AccumInfo accumInfo, Tree tree) { |
389 | 80 | try { | 79 | try { |
391 | 81 | return tree.getAccumulator(accumInfo.getType(), accumInfo.getIndex()); | 80 | switch(accumInfo.type) { |
392 | 81 | case SUM: return tree.getSumAccumulator(accumInfo.getIndex()); | ||
393 | 82 | case MAX: return tree.getMaxAccumulator(accumInfo.getIndex()); | ||
394 | 83 | case MIN: return tree.getMinAccumulator(accumInfo.getIndex()); | ||
395 | 84 | case SEQ: return tree.getSeqAccumulator(accumInfo.getIndex()); | ||
396 | 85 | default: | ||
397 | 86 | throw new IllegalStateException("Unknown accumulator type: " + accumInfo.type); | ||
398 | 87 | } | ||
399 | 82 | } catch (PersistitException e) { | 88 | } catch (PersistitException e) { |
400 | 83 | throw new PersistitAdapterException(e); | 89 | throw new PersistitAdapterException(e); |
401 | 84 | } | 90 | } |
402 | 85 | } | 91 | } |
403 | 86 | 92 | ||
404 | 87 | private Transaction getCurrentTrx() { | ||
405 | 88 | return getCurrentTrx(treeService); | ||
406 | 89 | } | ||
407 | 90 | |||
408 | 91 | private static Transaction getCurrentTrx(TreeService treeService) { | ||
409 | 92 | return treeService.getDb().getTransaction(); | ||
410 | 93 | } | ||
411 | 94 | |||
412 | 95 | private final TreeService treeService; | ||
413 | 96 | private final Accumulator accumulator; | 93 | private final Accumulator accumulator; |
414 | 97 | 94 | ||
415 | 98 | /** | 95 | /** |
416 | @@ -104,10 +101,16 @@ | |||
417 | 104 | * </p> | 101 | * </p> |
418 | 105 | */ | 102 | */ |
419 | 106 | public static enum AccumInfo { | 103 | public static enum AccumInfo { |
420 | 104 | /** Ordinal value as used in the hkey. Write once. Attached to the PK tree. */ | ||
421 | 107 | ORDINAL(0, Accumulator.Type.SUM), | 105 | ORDINAL(0, Accumulator.Type.SUM), |
422 | 106 | /** Size of a table or group index. Attached to PK tree and GI tree, respectively */ | ||
423 | 108 | ROW_COUNT(1, Accumulator.Type.SUM), | 107 | ROW_COUNT(1, Accumulator.Type.SUM), |
424 | 108 | /** Source of values for hidden primary keys. Attached to the PK tree. */ | ||
425 | 109 | UNIQUE_ID(2, Accumulator.Type.SEQ), | 109 | UNIQUE_ID(2, Accumulator.Type.SEQ), |
426 | 110 | /** Saves values from the MySQL adapter AUTO INCREMENT columns. Attached to the PK tree. */ | ||
427 | 110 | AUTO_INC(3, Accumulator.Type.SUM), | 111 | AUTO_INC(3, Accumulator.Type.SUM), |
428 | 112 | /** Source of values for SQL sequences. Attached to the sequence tree. */ | ||
429 | 113 | SEQUENCE(4, Accumulator.Type.SEQ) | ||
430 | 111 | ; | 114 | ; |
431 | 112 | 115 | ||
432 | 113 | AccumInfo(int index, Accumulator.Type type) { | 116 | AccumInfo(int index, Accumulator.Type type) { |
433 | 114 | 117 | ||
434 | === modified file 'src/main/java/com/akiban/server/MemoryOnlyTableStatusCache.java' | |||
435 | --- src/main/java/com/akiban/server/MemoryOnlyTableStatusCache.java 2013-03-22 20:05:57 +0000 | |||
436 | +++ src/main/java/com/akiban/server/MemoryOnlyTableStatusCache.java 2013-04-11 06:17:20 +0000 | |||
437 | @@ -102,13 +102,6 @@ | |||
438 | 102 | } | 102 | } |
439 | 103 | 103 | ||
440 | 104 | @Override | 104 | @Override |
441 | 105 | public synchronized void setUniqueId(long value) { | ||
442 | 106 | if (value < uniqueID) | ||
443 | 107 | throw new IllegalArgumentException("can't decrement uniqueID from " + uniqueID + " to " + value); | ||
444 | 108 | this.uniqueID = value; | ||
445 | 109 | } | ||
446 | 110 | |||
447 | 111 | @Override | ||
448 | 112 | public long getApproximateUniqueID() { | 105 | public long getApproximateUniqueID() { |
449 | 113 | return getUniqueID(); | 106 | return getUniqueID(); |
450 | 114 | } | 107 | } |
451 | 115 | 108 | ||
452 | === modified file 'src/main/java/com/akiban/server/PersistitAccumulatorTableStatusCache.java' | |||
453 | --- src/main/java/com/akiban/server/PersistitAccumulatorTableStatusCache.java 2013-03-22 20:05:57 +0000 | |||
454 | +++ src/main/java/com/akiban/server/PersistitAccumulatorTableStatusCache.java 2013-04-11 06:17:20 +0000 | |||
455 | @@ -18,7 +18,6 @@ | |||
456 | 18 | package com.akiban.server; | 18 | package com.akiban.server; |
457 | 19 | 19 | ||
458 | 20 | import com.akiban.qp.memoryadapter.MemoryTableFactory; | 20 | import com.akiban.qp.memoryadapter.MemoryTableFactory; |
459 | 21 | import com.akiban.server.error.AkibanInternalException; | ||
460 | 22 | import com.akiban.server.error.PersistitAdapterException; | 21 | import com.akiban.server.error.PersistitAdapterException; |
461 | 23 | import com.akiban.server.rowdata.IndexDef; | 22 | import com.akiban.server.rowdata.IndexDef; |
462 | 24 | import com.akiban.server.rowdata.RowDef; | 23 | import com.akiban.server.rowdata.RowDef; |
463 | @@ -138,27 +137,18 @@ | |||
464 | 138 | } | 137 | } |
465 | 139 | 138 | ||
466 | 140 | @Override | 139 | @Override |
467 | 141 | public void setUniqueId(long value) { | ||
468 | 142 | try { | ||
469 | 143 | this.uniqueID.set(value); | ||
470 | 144 | } catch (PersistitInterruptedException e) { | ||
471 | 145 | throw new PersistitAdapterException(e); | ||
472 | 146 | } | ||
473 | 147 | } | ||
474 | 148 | |||
475 | 149 | @Override | ||
476 | 150 | public int getTableID() { | 140 | public int getTableID() { |
477 | 151 | return expectedID; | 141 | return expectedID; |
478 | 152 | } | 142 | } |
479 | 153 | 143 | ||
480 | 154 | @Override | 144 | @Override |
481 | 155 | public void rowDeleted() { | 145 | public void rowDeleted() { |
483 | 156 | rowCount.updateAndGet(-1); | 146 | rowCount.sumAdd(-1); |
484 | 157 | } | 147 | } |
485 | 158 | 148 | ||
486 | 159 | @Override | 149 | @Override |
487 | 160 | public void rowsWritten(long count) { | 150 | public void rowsWritten(long count) { |
489 | 161 | rowCount.updateAndGet(count); | 151 | rowCount.sumAdd(count); |
490 | 162 | } | 152 | } |
491 | 163 | 153 | ||
492 | 164 | public void setOrdinal(int ordinal) throws PersistitInterruptedException { | 154 | public void setOrdinal(int ordinal) throws PersistitInterruptedException { |
493 | @@ -167,7 +157,7 @@ | |||
494 | 167 | 157 | ||
495 | 168 | @Override | 158 | @Override |
496 | 169 | public long createNewUniqueID() throws PersistitInterruptedException { | 159 | public long createNewUniqueID() throws PersistitInterruptedException { |
498 | 170 | return uniqueID.updateAndGet(1); | 160 | return uniqueID.seqAllocate(); |
499 | 171 | } | 161 | } |
500 | 172 | 162 | ||
501 | 173 | @Override | 163 | @Override |
502 | @@ -188,10 +178,10 @@ | |||
503 | 188 | } else { | 178 | } else { |
504 | 189 | checkExpectedRowDefID(expectedID, rowDef); | 179 | checkExpectedRowDefID(expectedID, rowDef); |
505 | 190 | Tree tree = getTreeForRowDef(rowDef); | 180 | Tree tree = getTreeForRowDef(rowDef); |
510 | 191 | ordinal = new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.ORDINAL, treeService, tree); | 181 | ordinal = new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.ORDINAL, tree); |
511 | 192 | rowCount = new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.ROW_COUNT, treeService, tree); | 182 | rowCount = new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.ROW_COUNT, tree); |
512 | 193 | uniqueID = new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.UNIQUE_ID, treeService, tree); | 183 | uniqueID = new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.UNIQUE_ID, tree); |
513 | 194 | autoIncrement = new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.AUTO_INC, treeService, tree); | 184 | autoIncrement = new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.AUTO_INC, tree); |
514 | 195 | } | 185 | } |
515 | 196 | } | 186 | } |
516 | 197 | 187 | ||
517 | @@ -240,11 +230,6 @@ | |||
518 | 240 | } | 230 | } |
519 | 241 | 231 | ||
520 | 242 | @Override | 232 | @Override |
521 | 243 | public void setUniqueId(long value) { | ||
522 | 244 | throw new UnsupportedOperationException(); | ||
523 | 245 | } | ||
524 | 246 | |||
525 | 247 | @Override | ||
526 | 248 | public long getApproximateUniqueID() { | 233 | public long getApproximateUniqueID() { |
527 | 249 | throw new UnsupportedOperationException(); | 234 | throw new UnsupportedOperationException(); |
528 | 250 | } | 235 | } |
529 | 251 | 236 | ||
530 | === modified file 'src/main/java/com/akiban/server/TableStatus.java' | |||
531 | --- src/main/java/com/akiban/server/TableStatus.java 2013-03-22 20:05:57 +0000 | |||
532 | +++ src/main/java/com/akiban/server/TableStatus.java 2013-04-11 06:17:20 +0000 | |||
533 | @@ -79,6 +79,4 @@ | |||
534 | 79 | void setRowCount(long rowCount); | 79 | void setRowCount(long rowCount); |
535 | 80 | 80 | ||
536 | 81 | long getApproximateUniqueID(); | 81 | long getApproximateUniqueID(); |
537 | 82 | |||
538 | 83 | void setUniqueId(long value); | ||
539 | 84 | } | 82 | } |
540 | 85 | 83 | ||
541 | === modified file 'src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java' | |||
542 | --- src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-03-22 20:05:57 +0000 | |||
543 | +++ src/main/java/com/akiban/server/service/dxl/BasicDDLFunctions.java 2013-04-11 06:17:20 +0000 | |||
544 | @@ -1162,8 +1162,7 @@ | |||
545 | 1162 | else { | 1162 | else { |
546 | 1163 | final Exchange ex = pStore.getExchange(session, index); | 1163 | final Exchange ex = pStore.getExchange(session, index); |
547 | 1164 | try { | 1164 | try { |
550 | 1165 | AccumulatorAdapter accum = | 1165 | AccumulatorAdapter accum = new AccumulatorAdapter(AccumInfo.ROW_COUNT, ex.getTree()); |
549 | 1166 | new AccumulatorAdapter(AccumInfo.ROW_COUNT, treeService(), ex.getTree()); | ||
551 | 1167 | accum.set(actual); | 1166 | accum.set(actual); |
552 | 1168 | } | 1167 | } |
553 | 1169 | finally { | 1168 | finally { |
554 | 1170 | 1169 | ||
555 | === modified file 'src/main/java/com/akiban/server/store/PersistitStore.java' | |||
556 | --- src/main/java/com/akiban/server/store/PersistitStore.java 2013-03-22 20:05:57 +0000 | |||
557 | +++ src/main/java/com/akiban/server/store/PersistitStore.java 2013-04-11 06:17:20 +0000 | |||
558 | @@ -610,7 +610,13 @@ | |||
559 | 610 | } | 610 | } |
560 | 611 | for (Map.Entry<RowDef, AtomicLong> hiddenPkEntry : bulkload.hiddenPks.entrySet()) { | 611 | for (Map.Entry<RowDef, AtomicLong> hiddenPkEntry : bulkload.hiddenPks.entrySet()) { |
561 | 612 | RowDef rowDef = hiddenPkEntry.getKey(); | 612 | RowDef rowDef = hiddenPkEntry.getKey(); |
563 | 613 | rowDef.getTableStatus().setUniqueId(hiddenPkEntry.getValue().get()); | 613 | TableStatus status = rowDef.getTableStatus(); |
564 | 614 | long target = hiddenPkEntry.getValue().get(); | ||
565 | 615 | long diff = target - status.getUniqueID(); | ||
566 | 616 | while(diff > 0) { | ||
567 | 617 | status.createNewUniqueID(); | ||
568 | 618 | --diff; | ||
569 | 619 | } | ||
570 | 614 | } | 620 | } |
571 | 615 | } | 621 | } |
572 | 616 | finally { | 622 | finally { |
573 | @@ -930,7 +936,7 @@ | |||
574 | 930 | try { | 936 | try { |
575 | 931 | iEx.removeAll(); | 937 | iEx.removeAll(); |
576 | 932 | if (index.isGroupIndex()) { | 938 | if (index.isGroupIndex()) { |
578 | 933 | new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.ROW_COUNT, treeService, iEx.getTree()).set(0); | 939 | new AccumulatorAdapter(AccumulatorAdapter.AccumInfo.ROW_COUNT, iEx.getTree()).set(0); |
579 | 934 | } | 940 | } |
580 | 935 | } catch (PersistitException e) { | 941 | } catch (PersistitException e) { |
581 | 936 | throw new PersistitAdapterException(e); | 942 | throw new PersistitAdapterException(e); |
582 | 937 | 943 | ||
583 | === modified file 'src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java' | |||
584 | --- src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java 2013-03-22 20:05:57 +0000 | |||
585 | +++ src/main/java/com/akiban/server/store/PersistitStoreSchemaManager.java 2013-04-11 06:17:20 +0000 | |||
586 | @@ -239,7 +239,6 @@ | |||
587 | 239 | private static final String DELAYED_TREE_KEY = "delayedTree"; | 239 | private static final String DELAYED_TREE_KEY = "delayedTree"; |
588 | 240 | 240 | ||
589 | 241 | private static final int SCHEMA_GEN_ACCUM_INDEX = 0; | 241 | private static final int SCHEMA_GEN_ACCUM_INDEX = 0; |
590 | 242 | private static final Accumulator.Type SCHEMA_GEN_ACCUM_TYPE = Accumulator.Type.SEQ; | ||
591 | 243 | 242 | ||
592 | 244 | // Changed from 1 to 2 due to incompatibility related to index row changes (see bug 985007) | 243 | // Changed from 1 to 2 due to incompatibility related to index row changes (see bug 985007) |
593 | 245 | private static final int PROTOBUF_PSSM_VERSION = 2; | 244 | private static final int PROTOBUF_PSSM_VERSION = 2; |
594 | @@ -806,14 +805,9 @@ | |||
595 | 806 | @Override | 805 | @Override |
596 | 807 | public void createSequence(Session session, Sequence sequence) { | 806 | public void createSequence(Session session, Sequence sequence) { |
597 | 808 | checkSequenceName(session, sequence.getSequenceName(), false); | 807 | checkSequenceName(session, sequence.getSequenceName(), false); |
599 | 809 | AkibanInformationSchema newAIS = AISMerge.mergeSequence(this.getAis(session), sequence); | 808 | AISMerge merge = AISMerge.newForOther(nameGenerator, getAis(session)); |
600 | 809 | AkibanInformationSchema newAIS = merge.mergeSequence(sequence); | ||
601 | 810 | saveAISChangeWithRowDefs(session, newAIS, Collections.singleton(sequence.getSchemaName())); | 810 | saveAISChangeWithRowDefs(session, newAIS, Collections.singleton(sequence.getSchemaName())); |
602 | 811 | try { | ||
603 | 812 | sequence.setStartWithAccumulator(treeService); | ||
604 | 813 | } catch (PersistitException e) { | ||
605 | 814 | LOG.error("Setting sequence starting value for sequence {} failed", sequence.getSequenceName().getDescription()); | ||
606 | 815 | throw wrapPersistitException(session, e); | ||
607 | 816 | } | ||
608 | 817 | } | 811 | } |
609 | 818 | 812 | ||
610 | 819 | /** Drop the given sequence from the current AIS. */ | 813 | /** Drop the given sequence from the current AIS. */ |
611 | @@ -1467,14 +1461,14 @@ | |||
612 | 1467 | return !curVer.equals(tableVer); | 1461 | return !curVer.equals(tableVer); |
613 | 1468 | } | 1462 | } |
614 | 1469 | 1463 | ||
616 | 1470 | private Accumulator getGenerationAccumulator(Session session) throws PersistitException { | 1464 | private Accumulator.SeqAccumulator getGenerationAccumulator(Session session) throws PersistitException { |
617 | 1471 | // treespace policy could split the _schema_ tree across volumes and give us multiple accumulators, which would | 1465 | // treespace policy could split the _schema_ tree across volumes and give us multiple accumulators, which would |
618 | 1472 | // be very bad. Work around that with a fake/constant schema name. It isn't a problem if this somehow got changed | 1466 | // be very bad. Work around that with a fake/constant schema name. It isn't a problem if this somehow got changed |
619 | 1473 | // across a restart. Really, we want a constant, system-like volume to put this in. | 1467 | // across a restart. Really, we want a constant, system-like volume to put this in. |
620 | 1474 | final String SCHEMA = "pssm"; | 1468 | final String SCHEMA = "pssm"; |
621 | 1475 | Exchange ex = schemaTreeExchange(session, SCHEMA); | 1469 | Exchange ex = schemaTreeExchange(session, SCHEMA); |
622 | 1476 | try { | 1470 | try { |
624 | 1477 | return ex.getTree().getAccumulator(SCHEMA_GEN_ACCUM_TYPE, SCHEMA_GEN_ACCUM_INDEX); | 1471 | return ex.getTree().getSeqAccumulator(SCHEMA_GEN_ACCUM_INDEX); |
625 | 1478 | } finally { | 1472 | } finally { |
626 | 1479 | treeService.releaseExchange(session, ex); | 1473 | treeService.releaseExchange(session, ex); |
627 | 1480 | } | 1474 | } |
628 | @@ -1482,16 +1476,15 @@ | |||
629 | 1482 | 1476 | ||
630 | 1483 | private long getGenerationSnapshot(Session session) { | 1477 | private long getGenerationSnapshot(Session session) { |
631 | 1484 | try { | 1478 | try { |
633 | 1485 | return getGenerationAccumulator(session).getSnapshotValue(treeService.getDb().getTransaction()); | 1479 | return getGenerationAccumulator(session).getSnapshotValue(); |
634 | 1486 | } catch(PersistitException e) { | 1480 | } catch(PersistitException e) { |
635 | 1487 | throw wrapPersistitException(session, e); | 1481 | throw wrapPersistitException(session, e); |
636 | 1488 | } | 1482 | } |
637 | 1489 | } | 1483 | } |
638 | 1490 | 1484 | ||
639 | 1491 | private long getNextGeneration(Session session) { | 1485 | private long getNextGeneration(Session session) { |
640 | 1492 | final int ACCUM_UPDATE_VALUE = 1; // irrelevant for SEQ types | ||
641 | 1493 | try { | 1486 | try { |
643 | 1494 | return getGenerationAccumulator(session).update(ACCUM_UPDATE_VALUE, treeService.getDb().getTransaction()); | 1487 | return getGenerationAccumulator(session).allocate(); |
644 | 1495 | } catch(PersistitException e) { | 1488 | } catch(PersistitException e) { |
645 | 1496 | throw wrapPersistitException(session, e); | 1489 | throw wrapPersistitException(session, e); |
646 | 1497 | } | 1490 | } |
647 | @@ -1538,14 +1531,6 @@ | |||
648 | 1538 | mergedTable.setMemoryTableFactory(factory); | 1531 | mergedTable.setMemoryTableFactory(factory); |
649 | 1539 | unSavedAISChangeWithRowDefs(session, newAIS); | 1532 | unSavedAISChangeWithRowDefs(session, newAIS); |
650 | 1540 | } | 1533 | } |
651 | 1541 | try { | ||
652 | 1542 | if (mergedTable.getIdentityColumn() != null) { | ||
653 | 1543 | mergedTable.getIdentityColumn().getIdentityGenerator().setStartWithAccumulator(treeService); | ||
654 | 1544 | } | ||
655 | 1545 | } catch (PersistitException ex) { | ||
656 | 1546 | LOG.error("Setting sequence starting value for table {} failed", mergedTable.getName().getDescription()); | ||
657 | 1547 | throw wrapPersistitException(session, ex); | ||
658 | 1548 | } | ||
659 | 1549 | return newName; | 1534 | return newName; |
660 | 1550 | } | 1535 | } |
661 | 1551 | 1536 | ||
662 | @@ -1690,8 +1675,28 @@ | |||
663 | 1690 | .colBigInt("map_size", false) | 1675 | .colBigInt("map_size", false) |
664 | 1691 | .colBigInt("outstanding_count", false) | 1676 | .colBigInt("outstanding_count", false) |
665 | 1692 | .colBigInt("task_queue_size", false); | 1677 | .colBigInt("task_queue_size", false); |
667 | 1693 | UserTable table = builder.ais().getUserTable(factory.getName()); | 1678 | |
668 | 1679 | final int IDENT_MAX = 128; | ||
669 | 1680 | builder.defaultSchema(TableName.SYS_SCHEMA); | ||
670 | 1681 | builder.procedure("seq_tree_reset") | ||
671 | 1682 | .language("java", Routine.CallingConvention.JAVA) | ||
672 | 1683 | .paramStringIn("seq_schema", IDENT_MAX) | ||
673 | 1684 | .paramStringIn("seq_name", IDENT_MAX) | ||
674 | 1685 | .paramLongIn("new_value") | ||
675 | 1686 | .externalName(SequenceFixUpRoutines.class.getCanonicalName(), "seq_tree_reset"); | ||
676 | 1687 | builder.procedure("seq_identity_default_to_always") | ||
677 | 1688 | .language("java", Routine.CallingConvention.JAVA) | ||
678 | 1689 | .paramStringIn("schema", IDENT_MAX) | ||
679 | 1690 | .paramStringIn("table", IDENT_MAX) | ||
680 | 1691 | .paramStringIn("column", IDENT_MAX) | ||
681 | 1692 | .externalName(SequenceFixUpRoutines.class.getCanonicalName(), "seq_identity_default_to_always"); | ||
682 | 1693 | |||
683 | 1694 | AkibanInformationSchema ais = builder.ais(); | ||
684 | 1695 | UserTable table = ais.getUserTable(factory.getName()); | ||
685 | 1694 | registerMemoryInformationSchemaTable(table, factory); | 1696 | registerMemoryInformationSchemaTable(table, factory); |
686 | 1697 | for(Routine routine : ais.getRoutines().values()) { | ||
687 | 1698 | registerSystemRoutine(routine); | ||
688 | 1699 | } | ||
689 | 1695 | } | 1700 | } |
690 | 1696 | 1701 | ||
691 | 1697 | 1702 | ||
692 | 1698 | 1703 | ||
693 | === added file 'src/main/java/com/akiban/server/store/SequenceFixUpRoutines.java' | |||
694 | --- src/main/java/com/akiban/server/store/SequenceFixUpRoutines.java 1970-01-01 00:00:00 +0000 | |||
695 | +++ src/main/java/com/akiban/server/store/SequenceFixUpRoutines.java 2013-04-11 06:17:20 +0000 | |||
696 | @@ -0,0 +1,139 @@ | |||
697 | 1 | /** | ||
698 | 2 | * Copyright (C) 2009-2013 Akiban Technologies, Inc. | ||
699 | 3 | * | ||
700 | 4 | * This program is free software: you can redistribute it and/or modify | ||
701 | 5 | * it under the terms of the GNU Affero General Public License as published by | ||
702 | 6 | * the Free Software Foundation, either version 3 of the License, or | ||
703 | 7 | * (at your option) any later version. | ||
704 | 8 | * | ||
705 | 9 | * This program is distributed in the hope that it will be useful, | ||
706 | 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
707 | 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
708 | 12 | * GNU Affero General Public License for more details. | ||
709 | 13 | * | ||
710 | 14 | * You should have received a copy of the GNU Affero General Public License | ||
711 | 15 | * along with this program. If not, see <http://www.gnu.org/licenses/>. | ||
712 | 16 | */ | ||
713 | 17 | |||
714 | 18 | package com.akiban.server.store; | ||
715 | 19 | |||
716 | 20 | import com.akiban.ais.AISCloner; | ||
717 | 21 | import com.akiban.ais.model.AkibanInformationSchema; | ||
718 | 22 | import com.akiban.ais.model.Column; | ||
719 | 23 | import com.akiban.ais.model.Sequence; | ||
720 | 24 | import com.akiban.ais.model.TableName; | ||
721 | 25 | import com.akiban.ais.model.UserTable; | ||
722 | 26 | import com.akiban.ais.protobuf.ProtobufWriter; | ||
723 | 27 | import com.akiban.ais.util.TableChange; | ||
724 | 28 | import com.akiban.server.error.NoSuchColumnException; | ||
725 | 29 | import com.akiban.server.error.NoSuchSchemaException; | ||
726 | 30 | import com.akiban.server.error.NoSuchSequenceException; | ||
727 | 31 | import com.akiban.server.error.NoSuchTableException; | ||
728 | 32 | import com.akiban.server.error.PersistitAdapterException; | ||
729 | 33 | import com.akiban.server.service.dxl.DXLFunctionsHook; | ||
730 | 34 | import com.akiban.server.service.dxl.DXLReadWriteLockHook; | ||
731 | 35 | import com.akiban.server.service.session.Session; | ||
732 | 36 | import com.akiban.server.service.tree.TreeService; | ||
733 | 37 | import com.akiban.sql.server.ServerCallContextStack; | ||
734 | 38 | import com.akiban.sql.server.ServerQueryContext; | ||
735 | 39 | import com.akiban.sql.server.ServerSession; | ||
736 | 40 | import com.persistit.exception.PersistitException; | ||
737 | 41 | |||
738 | 42 | import java.util.Arrays; | ||
739 | 43 | |||
740 | 44 | import static com.akiban.server.service.transaction.TransactionService.CloseableTransaction; | ||
741 | 45 | |||
742 | 46 | /** | ||
743 | 47 | * <p> | ||
744 | 48 | * Added in support of bug1167045. These routines allow for a manual fix of existing databases with sequences. | ||
745 | 49 | * </p> | ||
746 | 50 | * <p> | ||
747 | 51 | * Prior to 1.6.1, SEQUENCEs were backed by a SUM accumulator and used in a non-safe way. Particularly, rollbacks | ||
748 | 52 | * would cause value reuse upon restart. Post bug fix, they are backed by a SEQ under a different algorithm. | ||
749 | 53 | * </p> | ||
750 | 54 | * <p> | ||
751 | 55 | * seq_tree_rest allows for an existing sequence to be cleared and pegged at a new value. | ||
752 | 56 | * </p> | ||
753 | 57 | * <p> | ||
754 | 58 | * seq_identity_default_to_always allows for an IDENTITY column to be set to ALWAYS instead of DEFAULT, which | ||
755 | 59 | * is the new default behavior for SERIAL columns. | ||
756 | 60 | * </p> | ||
757 | 61 | */ | ||
758 | 62 | public class SequenceFixUpRoutines { | ||
759 | 63 | private static final DXLFunctionsHook.DXLFunction LOCK_FUNC = DXLFunctionsHook.DXLFunction.UNSPECIFIED_DDL_WRITE; | ||
760 | 64 | |||
761 | 65 | private SequenceFixUpRoutines() { | ||
762 | 66 | } | ||
763 | 67 | |||
764 | 68 | public static void seq_tree_reset(String seqSchema, String seqName, long newValue) throws InterruptedException { | ||
765 | 69 | if(!DXLReadWriteLockHook.only().isDDLLockEnabled()) { | ||
766 | 70 | throw new IllegalStateException("Unsafe to use with global lock disabled"); | ||
767 | 71 | } | ||
768 | 72 | |||
769 | 73 | final ServerQueryContext context = ServerCallContextStack.current().getContext(); | ||
770 | 74 | final ServerSession server = context.getServer(); | ||
771 | 75 | final Session session = server.getSession(); | ||
772 | 76 | if(!server.getSecurityService().isAccessible(session, seqSchema)) { | ||
773 | 77 | throw new NoSuchSchemaException(seqSchema); | ||
774 | 78 | } | ||
775 | 79 | |||
776 | 80 | // Global lock | ||
777 | 81 | DXLReadWriteLockHook.only().lock(session, LOCK_FUNC, -1); | ||
778 | 82 | try { | ||
779 | 83 | // Find sequence | ||
780 | 84 | Sequence seq = server.getDXL().ddlFunctions().getAIS(session).getSequence(new TableName(seqSchema, seqName)); | ||
781 | 85 | if(seq == null) { | ||
782 | 86 | throw new NoSuchSequenceException(seqSchema, seqName); | ||
783 | 87 | } | ||
784 | 88 | TreeService treeService = server.getTreeService(); | ||
785 | 89 | // Drop tree | ||
786 | 90 | treeService.getExchange(session, seq).removeTree(); | ||
787 | 91 | // Create tree | ||
788 | 92 | treeService.populateTreeCache(seq); | ||
789 | 93 | try(CloseableTransaction txn = server.getTransactionService().beginCloseableTransaction(session)) { | ||
790 | 94 | for(int i = 0; i < newValue; ++i) { | ||
791 | 95 | seq.nextValue(); | ||
792 | 96 | } | ||
793 | 97 | txn.commit(); | ||
794 | 98 | } | ||
795 | 99 | } catch(PersistitException e) { | ||
796 | 100 | throw new PersistitAdapterException(e); | ||
797 | 101 | } finally { | ||
798 | 102 | // unlock | ||
799 | 103 | DXLReadWriteLockHook.only().unlock(server.getSession(), LOCK_FUNC); | ||
800 | 104 | } | ||
801 | 105 | } | ||
802 | 106 | |||
803 | 107 | public static void seq_identity_default_to_always(String schema, String table, String column) { | ||
804 | 108 | final ServerQueryContext context = ServerCallContextStack.current().getContext(); | ||
805 | 109 | final ServerSession server = context.getServer(); | ||
806 | 110 | final Session session = server.getSession(); | ||
807 | 111 | if(!server.getSecurityService().isAccessible(session, schema)) { | ||
808 | 112 | throw new NoSuchSchemaException(schema); | ||
809 | 113 | } | ||
810 | 114 | |||
811 | 115 | TableName tableName = new TableName(schema, table); | ||
812 | 116 | AkibanInformationSchema ais = server.getAIS(); | ||
813 | 117 | UserTable curTable = ais.getUserTable(tableName); | ||
814 | 118 | if(curTable == null) { | ||
815 | 119 | throw new NoSuchTableException(tableName); | ||
816 | 120 | } | ||
817 | 121 | Column curColumn = curTable.getColumn(column); | ||
818 | 122 | if(curColumn == null) { | ||
819 | 123 | throw new NoSuchColumnException(column); | ||
820 | 124 | } | ||
821 | 125 | if(curColumn.getDefaultIdentity() == null) { | ||
822 | 126 | throw new IllegalArgumentException("Column " + column + " is not an IDENTITY"); | ||
823 | 127 | } | ||
824 | 128 | |||
825 | 129 | AkibanInformationSchema copy = AISCloner.clone(ais, new ProtobufWriter.SingleSchemaSelector(schema)); | ||
826 | 130 | UserTable newTable = copy.getUserTable(schema, table); | ||
827 | 131 | newTable.getColumn(column).setDefaultIdentity(false); | ||
828 | 132 | server.getDXL().ddlFunctions().alterTable( | ||
829 | 133 | session, tableName, newTable, | ||
830 | 134 | Arrays.asList(TableChange.createModify(column, column)), | ||
831 | 135 | Arrays.<TableChange>asList(), | ||
832 | 136 | context | ||
833 | 137 | ); | ||
834 | 138 | } | ||
835 | 139 | } | ||
836 | 0 | 140 | ||
837 | === modified file 'src/main/java/com/akiban/server/store/statistics/IndexStatisticsServiceImpl.java' | |||
838 | --- src/main/java/com/akiban/server/store/statistics/IndexStatisticsServiceImpl.java 2013-03-22 20:05:57 +0000 | |||
839 | +++ src/main/java/com/akiban/server/store/statistics/IndexStatisticsServiceImpl.java 2013-04-11 06:17:20 +0000 | |||
840 | @@ -151,7 +151,7 @@ | |||
841 | 151 | } | 151 | } |
842 | 152 | final Exchange ex = store.getExchange(session, index); | 152 | final Exchange ex = store.getExchange(session, index); |
843 | 153 | try { | 153 | try { |
845 | 154 | return AccumulatorAdapter.getSnapshot(AccumulatorAdapter.AccumInfo.ROW_COUNT, treeService, ex.getTree()); | 154 | return AccumulatorAdapter.getSnapshot(AccumulatorAdapter.AccumInfo.ROW_COUNT, ex.getTree()); |
846 | 155 | } | 155 | } |
847 | 156 | finally { | 156 | finally { |
848 | 157 | store.releaseExchange(session, ex); | 157 | store.releaseExchange(session, ex); |
849 | @@ -165,7 +165,7 @@ | |||
850 | 165 | } | 165 | } |
851 | 166 | final Exchange ex = store.getExchange(session, index); | 166 | final Exchange ex = store.getExchange(session, index); |
852 | 167 | try { | 167 | try { |
854 | 168 | return AccumulatorAdapter.getLiveValue(AccumulatorAdapter.AccumInfo.ROW_COUNT, treeService, ex.getTree()); | 168 | return AccumulatorAdapter.getLiveValue(AccumulatorAdapter.AccumInfo.ROW_COUNT, ex.getTree()); |
855 | 169 | } | 169 | } |
856 | 170 | finally { | 170 | finally { |
857 | 171 | store.releaseExchange(session, ex); | 171 | store.releaseExchange(session, ex); |
858 | 172 | 172 | ||
859 | === modified file 'src/main/java/com/akiban/sql/aisddl/TableDDL.java' | |||
860 | --- src/main/java/com/akiban/sql/aisddl/TableDDL.java 2013-03-22 20:05:57 +0000 | |||
861 | +++ src/main/java/com/akiban/sql/aisddl/TableDDL.java 2013-04-11 06:17:20 +0000 | |||
862 | @@ -208,15 +208,14 @@ | |||
863 | 208 | final String schemaName, final String tableName, int colpos) { | 208 | final String schemaName, final String tableName, int colpos) { |
864 | 209 | 209 | ||
865 | 210 | // Special handling for the "SERIAL" column type -> which is transformed to | 210 | // Special handling for the "SERIAL" column type -> which is transformed to |
867 | 211 | // BIGINT NOT NULL GENERATED BY DEFAULT AS IDENTITY (START WITH 1, INCREMENT BY 1) UNIQUE | 211 | // BIGINT NOT NULL GENERATED ALWAYS AS IDENTITY (START WITH 1, INCREMENT BY 1) UNIQUE |
868 | 212 | if (cdn.getType().getTypeName().equals("serial")) { | 212 | if (cdn.getType().getTypeName().equals("serial")) { |
869 | 213 | // BIGINT NOT NULL | 213 | // BIGINT NOT NULL |
870 | 214 | DataTypeDescriptor bigint = new DataTypeDescriptor (TypeId.BIGINT_ID, false); | 214 | DataTypeDescriptor bigint = new DataTypeDescriptor (TypeId.BIGINT_ID, false); |
871 | 215 | addColumn (builder, schemaName, tableName, cdn.getColumnName(), colpos, | 215 | addColumn (builder, schemaName, tableName, cdn.getColumnName(), colpos, |
872 | 216 | bigint, false, true, getColumnDefault(cdn)); | 216 | bigint, false, true, getColumnDefault(cdn)); |
876 | 217 | // GENERATED BY DEFAULT AS IDENTITY | 217 | // GENERATED ALWAYS AS IDENTITY |
877 | 218 | setAutoIncrement (builder, schemaName, tableName, cdn.getColumnName(), | 218 | setAutoIncrement (builder, schemaName, tableName, cdn.getColumnName(), false, 1, 1); |
875 | 219 | true, 1, 1); | ||
878 | 220 | // UNIQUE (KEY) | 219 | // UNIQUE (KEY) |
879 | 221 | String constraint = Index.UNIQUE_KEY_CONSTRAINT; | 220 | String constraint = Index.UNIQUE_KEY_CONSTRAINT; |
880 | 222 | builder.index(schemaName, tableName, cdn.getColumnName(), true, constraint); | 221 | builder.index(schemaName, tableName, cdn.getColumnName(), true, constraint); |
881 | 223 | 222 | ||
882 | === modified file 'src/test/java/com/akiban/server/rowdata/SchemaFactory.java' | |||
883 | --- src/test/java/com/akiban/server/rowdata/SchemaFactory.java 2013-03-22 20:05:57 +0000 | |||
884 | +++ src/test/java/com/akiban/server/rowdata/SchemaFactory.java 2013-04-11 06:17:20 +0000 | |||
885 | @@ -192,7 +192,8 @@ | |||
886 | 192 | 192 | ||
887 | 193 | @Override | 193 | @Override |
888 | 194 | public void createSequence(Session session, Sequence sequence) { | 194 | public void createSequence(Session session, Sequence sequence) { |
890 | 195 | ais = AISMerge.mergeSequence(ais, sequence); | 195 | AISMerge merge = AISMerge.newForOther(new DefaultNameGenerator(ais), ais); |
891 | 196 | ais = merge.mergeSequence(sequence); | ||
892 | 196 | } | 197 | } |
893 | 197 | 198 | ||
894 | 198 | @Override | 199 | @Override |
895 | 199 | 200 | ||
896 | === modified file 'src/test/java/com/akiban/server/test/it/dxl/AlterTableBasicIT.java' | |||
897 | --- src/test/java/com/akiban/server/test/it/dxl/AlterTableBasicIT.java 2013-03-22 20:05:57 +0000 | |||
898 | +++ src/test/java/com/akiban/server/test/it/dxl/AlterTableBasicIT.java 2013-04-11 06:17:20 +0000 | |||
899 | @@ -20,6 +20,7 @@ | |||
900 | 20 | import com.akiban.ais.AISCloner; | 20 | import com.akiban.ais.AISCloner; |
901 | 21 | import com.akiban.ais.model.AISBuilder; | 21 | import com.akiban.ais.model.AISBuilder; |
902 | 22 | import com.akiban.ais.model.AkibanInformationSchema; | 22 | import com.akiban.ais.model.AkibanInformationSchema; |
903 | 23 | import com.akiban.ais.model.Column; | ||
904 | 23 | import com.akiban.ais.model.Index; | 24 | import com.akiban.ais.model.Index; |
905 | 24 | import com.akiban.ais.model.Sequence; | 25 | import com.akiban.ais.model.Sequence; |
906 | 25 | import com.akiban.ais.model.TableName; | 26 | import com.akiban.ais.model.TableName; |
907 | @@ -1169,4 +1170,22 @@ | |||
908 | 1169 | public void changeColumnNameInGI_I() { | 1170 | public void changeColumnNameInGI_I() { |
909 | 1170 | changeColumnNameInGI("i", "i1", "i1_new"); | 1171 | changeColumnNameInGI("i", "i1", "i1_new"); |
910 | 1171 | } | 1172 | } |
911 | 1173 | |||
912 | 1174 | @Test | ||
913 | 1175 | public void alterColumnDefaultIdentity() { | ||
914 | 1176 | final int id = createTable(SCHEMA, C_TABLE, | ||
915 | 1177 | "id INT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY"); | ||
916 | 1178 | Column column = getUserTable(id).getColumn("id"); | ||
917 | 1179 | assertEquals("identity is default", true, column.getDefaultIdentity()); | ||
918 | 1180 | Sequence seq = column.getIdentityGenerator(); | ||
919 | 1181 | assertNotNull("id column has sequence", seq); | ||
920 | 1182 | |||
921 | 1183 | AkibanInformationSchema copy = AISCloner.clone(ais()); | ||
922 | 1184 | copy.getUserTable(id).getColumn("id").setDefaultIdentity(false); | ||
923 | 1185 | runAlter(ChangeLevel.METADATA, C_NAME, copy.getUserTable(id), | ||
924 | 1186 | Arrays.asList(TableChange.createModify("id", "id")), Arrays.<TableChange>asList()); | ||
925 | 1187 | |||
926 | 1188 | Column newColumn = getUserTable(id).getColumn("id"); | ||
927 | 1189 | assertEquals("altered is always", false, newColumn.getDefaultIdentity()); | ||
928 | 1190 | } | ||
929 | 1172 | } | 1191 | } |
930 | 1173 | 1192 | ||
931 | === modified file 'src/test/java/com/akiban/server/test/it/keyupdate/FixCountStarIT.java' | |||
932 | --- src/test/java/com/akiban/server/test/it/keyupdate/FixCountStarIT.java 2013-03-22 20:05:57 +0000 | |||
933 | +++ src/test/java/com/akiban/server/test/it/keyupdate/FixCountStarIT.java 2013-04-11 06:17:20 +0000 | |||
934 | @@ -101,7 +101,7 @@ | |||
935 | 101 | PersistitStore store = store().getPersistitStore(); | 101 | PersistitStore store = store().getPersistitStore(); |
936 | 102 | final Exchange ex = store.getExchange(session(), index); | 102 | final Exchange ex = store.getExchange(session(), index); |
937 | 103 | try { | 103 | try { |
939 | 104 | new AccumulatorAdapter(AccumInfo.ROW_COUNT, treeService(), ex.getTree()).set(newVal); | 104 | new AccumulatorAdapter(AccumInfo.ROW_COUNT, ex.getTree()).set(newVal); |
940 | 105 | } | 105 | } |
941 | 106 | catch (PersistitInterruptedException e) { | 106 | catch (PersistitInterruptedException e) { |
942 | 107 | throw new PersistitAdapterException(e); | 107 | throw new PersistitAdapterException(e); |
943 | 108 | 108 | ||
944 | === modified file 'src/test/java/com/akiban/sql/aisddl/SequenceDDLIT.java' | |||
945 | --- src/test/java/com/akiban/sql/aisddl/SequenceDDLIT.java 2013-03-22 20:05:57 +0000 | |||
946 | +++ src/test/java/com/akiban/sql/aisddl/SequenceDDLIT.java 2013-04-11 06:17:20 +0000 | |||
947 | @@ -21,6 +21,7 @@ | |||
948 | 21 | import static org.junit.Assert.assertNotNull; | 21 | import static org.junit.Assert.assertNotNull; |
949 | 22 | import static org.junit.Assert.fail; | 22 | import static org.junit.Assert.fail; |
950 | 23 | 23 | ||
951 | 24 | import com.akiban.ais.model.Sequence; | ||
952 | 24 | import org.junit.Test; | 25 | import org.junit.Test; |
953 | 25 | 26 | ||
954 | 26 | import com.akiban.ais.model.TableName; | 27 | import com.akiban.ais.model.TableName; |
955 | @@ -91,5 +92,56 @@ | |||
956 | 91 | executeDDL(sql); | 92 | executeDDL(sql); |
957 | 92 | assertEquals(Collections.singletonList(MessageFormat.format(ErrorCode.NO_SUCH_SEQUENCE.getMessage(), "test", "not_exists")), getWarnings()); | 93 | assertEquals(Collections.singletonList(MessageFormat.format(ErrorCode.NO_SUCH_SEQUENCE.getMessage(), "test", "not_exists")), getWarnings()); |
958 | 93 | } | 94 | } |
960 | 94 | 95 | ||
961 | 96 | @Test | ||
962 | 97 | public void durableAfterRollbackAndRestart() throws Exception { | ||
963 | 98 | TableName seqName = new TableName("test", "s1"); | ||
964 | 99 | String sql = "CREATE SEQUENCE "+seqName+" START WITH 1 INCREMENT BY 1"; | ||
965 | 100 | executeDDL(sql); | ||
966 | 101 | Sequence s1 = ais().getSequence(seqName); | ||
967 | 102 | assertNotNull("s1", s1); | ||
968 | 103 | |||
969 | 104 | txnService().beginTransaction(session()); | ||
970 | 105 | assertEquals("start val a", 0, s1.currentValue()); | ||
971 | 106 | assertEquals("next val a", 1, s1.nextValue()); | ||
972 | 107 | txnService().commitTransaction(session()); | ||
973 | 108 | |||
974 | 109 | txnService().beginTransaction(session()); | ||
975 | 110 | assertEquals("next val b", 2, s1.nextValue()); | ||
976 | 111 | assertEquals("cur val b", 2, s1.currentValue()); | ||
977 | 112 | txnService().rollbackTransactionIfOpen(session()); | ||
978 | 113 | |||
979 | 114 | txnService().beginTransaction(session()); | ||
980 | 115 | assertEquals("cur val c", 1, s1.currentValue()); | ||
981 | 116 | // Expected gap, see nextValue() impl | ||
982 | 117 | assertEquals("next val c", 3, s1.nextValue()); | ||
983 | 118 | txnService().commitTransaction(session()); | ||
984 | 119 | |||
985 | 120 | safeRestartTestServices(); | ||
986 | 121 | |||
987 | 122 | s1 = ais().getSequence(seqName); | ||
988 | 123 | txnService().beginTransaction(session()); | ||
989 | 124 | assertEquals("cur val after restart", 3, s1.currentValue()); | ||
990 | 125 | assertEquals("next val after restart", 4, s1.nextValue()); | ||
991 | 126 | txnService().commitTransaction(session()); | ||
992 | 127 | } | ||
993 | 128 | |||
994 | 129 | @Test | ||
995 | 130 | public void freshValueAfterDropAndRecreate() throws Exception { | ||
996 | 131 | final TableName seqName = new TableName("test", "s2"); | ||
997 | 132 | final String create = "CREATE SEQUENCE "+seqName+" START WITH 1 INCREMENT BY 1"; | ||
998 | 133 | final String drop = "DROP SEQUENCE "+seqName+" RESTRICT"; | ||
999 | 134 | for(int i = 1; i <= 2; ++i) { | ||
1000 | 135 | executeDDL(create); | ||
1001 | 136 | Sequence s1 = ais().getSequence(seqName); | ||
1002 | 137 | assertNotNull("s1, loop"+i, s1); | ||
1003 | 138 | |||
1004 | 139 | txnService().beginTransaction(session()); | ||
1005 | 140 | assertEquals("start val, loop"+i, 0, s1.currentValue()); | ||
1006 | 141 | assertEquals("next val, loop"+i, 1, s1.nextValue()); | ||
1007 | 142 | txnService().commitTransaction(session()); | ||
1008 | 143 | |||
1009 | 144 | executeDDL(drop); | ||
1010 | 145 | } | ||
1011 | 146 | } | ||
1012 | 95 | } | 147 | } |
1013 | 96 | 148 | ||
1014 | === modified file 'src/test/java/com/akiban/sql/aisddl/TableDDLIT.java' | |||
1015 | --- src/test/java/com/akiban/sql/aisddl/TableDDLIT.java 2013-03-22 20:05:57 +0000 | |||
1016 | +++ src/test/java/com/akiban/sql/aisddl/TableDDLIT.java 2013-04-11 06:17:20 +0000 | |||
1017 | @@ -367,7 +367,7 @@ | |||
1018 | 367 | assertEquals (1, column.getIdentityGenerator().getStartsWith()); | 367 | assertEquals (1, column.getIdentityGenerator().getStartsWith()); |
1019 | 368 | assertEquals (1, column.getIdentityGenerator().getIncrement()); | 368 | assertEquals (1, column.getIdentityGenerator().getIncrement()); |
1020 | 369 | assertNotNull(column.getDefaultIdentity()); | 369 | assertNotNull(column.getDefaultIdentity()); |
1022 | 370 | assertTrue(column.getDefaultIdentity().booleanValue()); | 370 | assertFalse(column.getDefaultIdentity()); |
1023 | 371 | 371 | ||
1024 | 372 | assertNotNull (table.getIndex("c1")); | 372 | assertNotNull (table.getIndex("c1")); |
1025 | 373 | Index index = table.getIndex("c1"); | 373 | Index index = table.getIndex("c1"); |
1026 | 374 | 374 | ||
1027 | === modified file 'src/test/java/com/akiban/sql/pg/PostgresServerMiscYamlIT.java' | |||
1028 | --- src/test/java/com/akiban/sql/pg/PostgresServerMiscYamlIT.java 2013-03-22 20:05:57 +0000 | |||
1029 | +++ src/test/java/com/akiban/sql/pg/PostgresServerMiscYamlIT.java 2013-04-11 06:17:20 +0000 | |||
1030 | @@ -31,6 +31,8 @@ | |||
1031 | 31 | import java.io.FileFilter; | 31 | import java.io.FileFilter; |
1032 | 32 | import java.util.ArrayList; | 32 | import java.util.ArrayList; |
1033 | 33 | import java.util.Collection; | 33 | import java.util.Collection; |
1034 | 34 | import java.util.Collections; | ||
1035 | 35 | import java.util.HashMap; | ||
1036 | 34 | import java.util.Map; | 36 | import java.util.Map; |
1037 | 35 | import java.util.regex.Pattern; | 37 | import java.util.regex.Pattern; |
1038 | 36 | 38 | ||
1039 | @@ -82,7 +84,12 @@ | |||
1040 | 82 | 84 | ||
1041 | 83 | @Override | 85 | @Override |
1042 | 84 | protected Map<String, String> startupConfigProperties() { | 86 | protected Map<String, String> startupConfigProperties() { |
1044 | 85 | return uniqueStartupConfigProperties(getClass()); | 87 | // TODO: Remove whenever test-seq-fixup-routines.yaml no longer exists |
1045 | 88 | Map<String, String> props = new HashMap(); | ||
1046 | 89 | props.put("akserver.dxl.use_global_lock", "true"); | ||
1047 | 90 | props.putAll(uniqueStartupConfigProperties(getClass())); | ||
1048 | 91 | return props; | ||
1049 | 92 | //return uniqueStartupConfigProperties(getClass()); | ||
1050 | 86 | } | 93 | } |
1051 | 87 | 94 | ||
1052 | 88 | @Test | 95 | @Test |
1053 | 89 | 96 | ||
1054 | === added file 'src/test/resources/com/akiban/sql/pg/yaml/functional/test-seq-fixup-routines.yaml' | |||
1055 | --- src/test/resources/com/akiban/sql/pg/yaml/functional/test-seq-fixup-routines.yaml 1970-01-01 00:00:00 +0000 | |||
1056 | +++ src/test/resources/com/akiban/sql/pg/yaml/functional/test-seq-fixup-routines.yaml 2013-04-11 06:17:20 +0000 | |||
1057 | @@ -0,0 +1,40 @@ | |||
1058 | 1 | # Can go away whenever SequenceFixUpRoutines does | ||
1059 | 2 | |||
1060 | 3 | # Requires global lock enabled, skip in FTS | ||
1061 | 4 | --- | ||
1062 | 5 | - Properties: sys-aksql | ||
1063 | 6 | - suppressed: true | ||
1064 | 7 | |||
1065 | 8 | # Re-set a sequence | ||
1066 | 9 | --- | ||
1067 | 10 | - Statement: CREATE SEQUENCE s1 START WITH 1 INCREMENT BY 1 | ||
1068 | 11 | --- | ||
1069 | 12 | - Statement: SELECT NEXT VALUE FOR s1 | ||
1070 | 13 | - output: [[1]] | ||
1071 | 14 | --- | ||
1072 | 15 | - Statement: CALL sys.seq_tree_reset('test', 's1', 150) | ||
1073 | 16 | --- | ||
1074 | 17 | - Statement: SELECT CURRENT VALUE FOR s1 | ||
1075 | 18 | - output: [[150]] | ||
1076 | 19 | --- | ||
1077 | 20 | - Statement: DROP SEQUENCE s1 RESTRICT | ||
1078 | 21 | |||
1079 | 22 | # ALTER BY DEFAULT to ALWAYS | ||
1080 | 23 | --- | ||
1081 | 24 | - Statement: CREATE TABLE t(id INT NOT NULL PRIMARY KEY GENERATED BY DEFAULT AS IDENTITY (START WITH 5)) | ||
1082 | 25 | --- | ||
1083 | 26 | - Statement: SELECT identity_generation FROM information_schema.columns WHERE table_name='t' AND column_name='id' | ||
1084 | 27 | - output: [['BY DEFAULT']] | ||
1085 | 28 | --- | ||
1086 | 29 | - Statement: CALL sys.seq_identity_default_to_always('test', 't', 'id') | ||
1087 | 30 | --- | ||
1088 | 31 | - Statement: SELECT identity_generation FROM information_schema.columns WHERE table_name='t' AND column_name='id' | ||
1089 | 32 | - output: [['ALWAYS']] | ||
1090 | 33 | --- | ||
1091 | 34 | # Expect value to be ignored due to ALWAYS | ||
1092 | 35 | - Statement: INSERT INTO t VALUES (100) | ||
1093 | 36 | --- | ||
1094 | 37 | - Statement: SELECT * FROM t | ||
1095 | 38 | - output: [[5]] | ||
1096 | 39 | --- | ||
1097 | 40 | - Statement: DROP TABLE t | ||
1098 | 0 | 41 | ||
1099 | === modified file 'src/test/resources/com/akiban/sql/pg/yaml/functional/test-sequence.yaml' | |||
1100 | --- src/test/resources/com/akiban/sql/pg/yaml/functional/test-sequence.yaml 2012-09-26 03:50:12 +0000 | |||
1101 | +++ src/test/resources/com/akiban/sql/pg/yaml/functional/test-sequence.yaml 2013-04-11 06:17:20 +0000 | |||
1102 | @@ -95,5 +95,53 @@ | |||
1103 | 95 | --- | 95 | --- |
1104 | 96 | - Statement: create sequence bad_sequence start with 1 increment by 1 minvalue 1 maxvalue 1 no cycle; | 96 | - Statement: create sequence bad_sequence start with 1 increment by 1 minvalue 1 maxvalue 1 no cycle; |
1105 | 97 | - error: [50020] | 97 | - error: [50020] |
1106 | 98 | |||
1107 | 99 | |||
1108 | 100 | --- | ||
1109 | 101 | - Statement: create sequence sequence5 start with 3 increment by 3 minvalue -5 maxvalue 5 cycle; | ||
1110 | 102 | --- | ||
1111 | 103 | - Statement: select next value for sequence5 | ||
1112 | 104 | - output: [[3]] | ||
1113 | 105 | --- | ||
1114 | 106 | - Statement: select next value for sequence5 | ||
1115 | 107 | - output: [[-5]] | ||
1116 | 108 | --- | ||
1117 | 109 | - Statement: select next value for sequence5 | ||
1118 | 110 | - output: [[-2]] | ||
1119 | 111 | --- | ||
1120 | 112 | - Statement: select next value for sequence5 | ||
1121 | 113 | - output: [[1]] | ||
1122 | 114 | --- | ||
1123 | 115 | - Statement: select next value for sequence5 | ||
1124 | 116 | - output: [[4]] | ||
1125 | 117 | --- | ||
1126 | 118 | - Statement: select current value for sequence5 | ||
1127 | 119 | - output: [[4]] | ||
1128 | 120 | --- | ||
1129 | 121 | - Statement: drop sequence sequence5 restrict | ||
1130 | 122 | |||
1131 | 123 | --- | ||
1132 | 124 | - Statement: create sequence sequence6 start with 3 increment by -3 minvalue -5 maxvalue 5 cycle; | ||
1133 | 125 | --- | ||
1134 | 126 | - Statement: select next value for sequence6 | ||
1135 | 127 | - output: [[3]] | ||
1136 | 128 | --- | ||
1137 | 129 | - Statement: select next value for sequence6 | ||
1138 | 130 | - output: [[0]] | ||
1139 | 131 | --- | ||
1140 | 132 | - Statement: select next value for sequence6 | ||
1141 | 133 | - output: [[-3]] | ||
1142 | 134 | --- | ||
1143 | 135 | - Statement: select next value for sequence6 | ||
1144 | 136 | - output: [[5]] | ||
1145 | 137 | --- | ||
1146 | 138 | - Statement: select next value for sequence6 | ||
1147 | 139 | - output: [[2]] | ||
1148 | 140 | --- | ||
1149 | 141 | - Statement: select current value for sequence6 | ||
1150 | 142 | - output: [[2]] | ||
1151 | 143 | --- | ||
1152 | 144 | - Statement: drop sequence sequence6 restrict | ||
1153 | 145 | |||
1154 | 98 | ... | 146 | ... |
1155 | 99 | 147 |
After several "no wait, oh, ok" moments I will say this addresses all of the issues it presents.