File D:\maven-qcr-plugin-testsunitaires\qcr4java\h2-1.3.170-sources\target\site\qc\lecode\index\MultiVersionIndex.java.html

1 /*
2 * Copyright 2004-2011 H2 Group. Multiple-Licensed under the H2 License,
3 * Version 1.0, and under the Eclipse Public License, Version 1.0
4 * (http://h2database.com/html/license.html).
5 * Initial Developer: H2 Group
6 */
7 package org.h2.index;
8
9 import java.util.ArrayList;
10 import org.h2.engine.Database;
11 import org.h2.engine.DbObject;
12 import org.h2.engine.Session;
13 import org.h2.message.DbException;
14 import org.h2.result.Row;
15 import org.h2.result.SearchRow;
16 import org.h2.schema.Schema;
17 import org.h2.table.Column;
18 import org.h2.table.IndexColumn;
19 import org.h2.table.RegularTable;
20 import org.h2.table.Table;
21 import org.h2.table.TableFilter;
22 import org.h2.value.Value;
23 import org.h2.value.ValueNull;
24
25 /**
26 * A multi-version index is a combination of a regular index,
27 * and a in-memory tree index that contains uncommitted changes.
28 * Uncommitted changes can include new rows, and deleted rows.
29 */
30 public class MultiVersionIndex implements Index {
31
32 private final Index base;
33 private final TreeIndex delta;
34 private final RegularTable table;
35 private final Object sync;
36 private final Column firstColumn;
37
38 public MultiVersionIndex(Index base, RegularTable table) {
39 this.base = base;
40 this.table = table;
41 IndexType deltaIndexType = IndexType.createNonUnique(false);
42 this.delta = new TreeIndex(table, -1, "DELTA", base.getIndexColumns(), deltaIndexType);
43 delta.setMultiVersion(true);
44 this.sync = base.getDatabase();
45 this.firstColumn = base.getColumns()[0];
46 }
47
48 public void add(Session session, Row row) {
49 synchronized (sync) {
50 base.add(session, row);
51 if (removeIfExists(session, row)) {
52 // for example rolling back an delete operation
53 } else if (row.getSessionId() != 0) {
54 // don't insert rows that are added when creating an index
55 delta.add(session, row);
56 }
57 }
58 }
59
60 public void close(Session session) {
61 synchronized (sync) {
62 base.close(session);
63 }
64 }
65
66 public Cursor find(TableFilter filter, SearchRow first, SearchRow last) {
67 synchronized (sync) {
68 Cursor baseCursor = base.find(filter, first, last);
69 Cursor deltaCursor = delta.find(filter, first, last);
70 return new MultiVersionCursor(filter.getSession(), this, baseCursor, deltaCursor, sync);
71 }
72 }
73
74 public Cursor find(Session session, SearchRow first, SearchRow last) {
75 synchronized (sync) {
76 Cursor baseCursor = base.find(session, first, last);
77 Cursor deltaCursor = delta.find(session, first, last);
78 return new MultiVersionCursor(session, this, baseCursor, deltaCursor, sync);
79 }
80 }
81
82 public Cursor findNext(Session session, SearchRow first, SearchRow last) {
83 throw DbException.throwInternalError();
84 }
85
86 public boolean canFindNext() {
87 // TODO possible, but more complicated
88 return false;
89 }
90
91 public boolean canGetFirstOrLast() {
92 return base.canGetFirstOrLast() && delta.canGetFirstOrLast();
93 }
94
95 public Cursor findFirstOrLast(Session session, boolean first) {
96 if (first) {
97 // TODO optimization: this loops through NULL elements
98 Cursor cursor = find(session, null, null);
99 while (cursor.next()) {
100 SearchRow row = cursor.getSearchRow();
101 Value v = row.getValue(firstColumn.getColumnId());
102 if (v != ValueNull.INSTANCE) {
103 return cursor;
104 }
105 }
106 return cursor;
107 }
108 Cursor baseCursor = base.findFirstOrLast(session, false);
109 Cursor deltaCursor = delta.findFirstOrLast(session, false);
110 MultiVersionCursor cursor = new MultiVersionCursor(session, this, baseCursor, deltaCursor, sync);
111 cursor.loadCurrent();
112 // TODO optimization: this loops through NULL elements
113 while (cursor.previous()) {
114 SearchRow row = cursor.getSearchRow();
115 if (row == null) {
116 break;
117 }
118 Value v = row.getValue(firstColumn.getColumnId());
119 if (v != ValueNull.INSTANCE) {
120 return cursor;
121 }
122 }
123 return cursor;
124 }
125
126 public double getCost(Session session, int[] masks) {
127 return base.getCost(session, masks);
128 }
129
130 public boolean needRebuild() {
131 return base.needRebuild();
132 }
133
134 /**
135 * Check if there is an uncommitted row with the given key
136 * within a different session.
137 *
138 * @param session the original session
139 * @param row the row (only the key is checked)
140 * @return true if there is an uncommitted row
141 */
142 public boolean isUncommittedFromOtherSession(Session session, Row row) {
143 Cursor c = delta.find(session, row, row);
144 while (c.next()) {
145 Row r = c.get();
146 return r.getSessionId() != session.getId();
147 }
148 return false;
149 }
150
151 private boolean removeIfExists(Session session, Row row) {
152 // maybe it was inserted by the same session just before
153 Cursor c = delta.find(session, row, row);
154 while (c.next()) {
155 Row r = c.get();
156 if (r.getKey() == row.getKey() && r.getVersion() == row.getVersion()) {
157 if (r != row && table.getScanIndex(session).compareRows(r, row) != 0) {
158 row.setVersion(r.getVersion() + 1);
159 } else {
160 delta.remove(session, r);
161 return true;
162 }
163 }
164 }
165 return false;
166 }
167
168 public void remove(Session session, Row row) {
169 synchronized (sync) {
170 base.remove(session, row);
171 if (removeIfExists(session, row)) {
172 // added and deleted in the same transaction: no change
173 } else {
174 delta.add(session, row);
175 }
176 }
177 }
178
179 public void remove(Session session) {
180 synchronized (sync) {
181 base.remove(session);
182 }
183 }
184
185 public void truncate(Session session) {
186 synchronized (sync) {
187 delta.truncate(session);
188 base.truncate(session);
189 }
190 }
191
192 public void commit(int operation, Row row) {
193 synchronized (sync) {
194 removeIfExists(null, row);
195 }
196 }
197
198 public int compareRows(SearchRow rowData, SearchRow compare) {
199 return base.compareRows(rowData, compare);
200 }
201
202 public int getColumnIndex(Column col) {
203 return base.getColumnIndex(col);
204 }
205
206 public Column[] getColumns() {
207 return base.getColumns();
208 }
209
210 public IndexColumn[] getIndexColumns() {
211 return base.getIndexColumns();
212 }
213
214 public String getCreateSQL() {
215 return base.getCreateSQL();
216 }
217
218 public String getCreateSQLForCopy(Table forTable, String quotedName) {
219 return base.getCreateSQLForCopy(forTable, quotedName);
220 }
221
222 public String getDropSQL() {
223 return base.getDropSQL();
224 }
225
226 public IndexType getIndexType() {
227 return base.getIndexType();
228 }
229
230 public String getPlanSQL() {
231 return base.getPlanSQL();
232 }
233
234 public long getRowCount(Session session) {
235 return base.getRowCount(session);
236 }
237
238 public Table getTable() {
239 return base.getTable();
240 }
241
242 public int getType() {
243 return base.getType();
244 }
245
246 public void removeChildrenAndResources(Session session) {
247 synchronized (sync) {
248 table.removeIndex(this);
249 remove(session);
250 }
251 }
252
253 public String getSQL() {
254 return base.getSQL();
255 }
256
257 public Schema getSchema() {
258 return base.getSchema();
259 }
260
261 public void checkRename() {
262 base.checkRename();
263 }
264
265 public ArrayList<DbObject> getChildren() {
266 return base.getChildren();
267 }
268
269 public String getComment() {
270 return base.getComment();
271 }
272
273 public Database getDatabase() {
274 return base.getDatabase();
275 }
276
277 public int getId() {
278 return base.getId();
279 }
280
281 public String getName() {
282 return base.getName();
283 }
284
285 public boolean isTemporary() {
286 return base.isTemporary();
287 }
288
289 public void rename(String newName) {
290 base.rename(newName);
291 }
292
293 public void setComment(String comment) {
294 base.setComment(comment);
295 }
296
297 public void setTemporary(boolean temporary) {
298 base.setTemporary(temporary);
299 }
300
301 public long getRowCountApproximation() {
302 return base.getRowCountApproximation();
303 }
304
305 public Index getBaseIndex() {
306 return base;
307 }
308
309 public Row getRow(Session session, long key) {
310 return base.getRow(session, key);
311 }
312
313 public boolean isHidden() {
314 return base.isHidden();
315 }
316
317 public boolean isRowIdIndex() {
318 return base.isRowIdIndex() && delta.isRowIdIndex();
319 }
320
321 public boolean canScan() {
322 return base.canScan();
323 }
324
325 public void setSortedInsertMode(boolean sortedInsertMode) {
326 base.setSortedInsertMode(sortedInsertMode);
327 delta.setSortedInsertMode(sortedInsertMode);
328 }
329
330 }
331