00001
package com.quadcap.sql;
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
import java.io.BufferedWriter;
00042
import java.io.File;
00043
import java.io.FileOutputStream;
00044
import java.io.IOException;
00045
import java.io.OutputStream;
00046
import java.io.OutputStreamWriter;
00047
import java.io.PrintWriter;
00048
00049
import java.util.ArrayList;
00050
import java.util.Calendar;
00051
import java.util.Collection;
00052
import java.util.Enumeration;
00053
import java.util.Iterator;
00054
import java.util.HashMap;
00055
import java.util.List;
00056
import java.util.Map;
00057
import java.util.Properties;
00058
00059
import java.util.zip.GZIPOutputStream;
00060
00061
import java.sql.SQLException;
00062
00063
import com.quadcap.sql.file.BlockFile;
00064
import com.quadcap.sql.file.ByteUtil;
00065
import com.quadcap.sql.file.Datafile;
00066
import com.quadcap.sql.file.Log;
00067
import com.quadcap.sql.file.SubPageManager;
00068
00069
import com.quadcap.sql.index.BCursor;
00070
import com.quadcap.sql.index.Btree;
00071
00072
import com.quadcap.sql.lock.Transaction;
00073
00074
import com.quadcap.util.collections.LongIterator;
00075
import com.quadcap.util.collections.LongMap;
00076
00077
import com.quadcap.util.ConfigString;
00078
import com.quadcap.util.Debug;
00079
import com.quadcap.util.Util;
00080
00081
00082
00083
00084
00085
00086 public class Database extends Datafile {
00087 QDriver driver;
00088 Btree
tableIndex;
00089
00090 Btree
indexIndex;
00091 Btree
blobPermRefCounts;
00092 Map
tableMap =
new HashMap();
00093 MultiSet forwardDeps = null;
00094 MultiSet reverseDeps = null;
00095 long rootBlock = 0;
00096 public DatabaseRoot nroot;
00097
00098
00099
00100 LongMap
blobMorgue =
new LongMap(32);
00101
00102
00103 LongMap
blobActivity =
new LongMap(128);
00104
00105
00106 int connectionCount = 0;
00107 int closeCount = 0;
00108 long nextTransId = 0;
00109
00110 public Object
driverLock;
00111
00112
static final ConfigString
backupClass
00113 = ConfigString.find(
"qed.backupClass",
00114
"com.quadcap.sql.tools.XmlDump");
00115
00116
00117
00118 public Database() {}
00119
00120 public void init(
QDriver driver, String url,
00121 String fileName, Properties props)
00122
throws IOException, SQLException
00123 {
00124
this.driver =
driver;
00125 init(url, fileName, props);
00126 }
00127
00128
00129
00130
00131 public void createRoot(String fileName, Properties props)
00132
throws IOException
00133 {
00134
this.rootBlock = getFile().getUserBlock(0);
00135
this.root =
this.nroot =
new DatabaseRoot(
this, fileName, props);
00136
if (!readOnly && !
inMemory) {
00137
new File(fileName,
"logfile").delete();
00138
flushRoot();
00139 }
00140 }
00141
00142
00143
00144
00145 public void readRoot() throws IOException {
00146
this.rootBlock = getFile().getUserBlock(0);
00147 root =
nroot = (
DatabaseRoot)file.getObject(
rootBlock);
00148 nroot.setDatabase(
this);
00149 }
00150
00151
00152
00153
00154 public void flushRoot() throws IOException {
00155
if (!
inMemory && !readOnly) {
00156 getFile().updateObject(
rootBlock, root);
00157 }
00158 }
00159
00160
00161
00162
00163 public void bootFromRoot(
boolean restart)
throws IOException {
00164
nextTransId = root.getNextTransId();
00165
nroot.
setNextTransId((
nextTransId | 0xff) + 1);
00166
00167
blobPermRefCounts =
new Btree(file,
00168
nroot.
getBlobRefCountRoot(), !restart);
00169
tableIndex =
new Btree(file,
nroot.
getRelationIndexNode(), !restart);
00170
indexIndex =
new Btree(file,
nroot.
getIndexIndexNode(), !restart);
00171
forwardDeps =
00172
new MultiSet(
new Btree(file,
nroot.
getForwardDepsNode(),
00173 !restart));
00174
reverseDeps =
00175
new MultiSet(
new Btree(file,
nroot.
getReverseDepsNode(),
00176 !restart));
00177 }
00178
00179
00180
00181
00182 public long getNextTransId() throws IOException {
00183
synchronized (fileLock) {
00184
long t =
nextTransId++;
00185
if (!
inMemory && (nextTransId & 0xff) == 0) {
00186
nroot.
setNextTransId(nextTransId + 0x100);
00187
flushRoot();
00188 }
00189
return t;
00190 }
00191 }
00192
00193
00194
00195
00196 public void maybeBackup() throws IOException {
00197
if (
inMemory)
return;
00198
00199
int days =
getBackupDays();
00200
if (days == 0)
return;
00201
00202
00203 Calendar now = Calendar.getInstance();
00204
int nowDay = now.get(Calendar.DAY_OF_WEEK);
00205
if (((days >> nowDay) & 1) == 0)
return;
00206
00207
00208
int time =
getBackupTime();
00209
int today = now.get(Calendar.DAY_OF_YEAR);
00210
int nowTime =
00211 now.get(Calendar.HOUR_OF_DAY) * 60 +
00212 now.get(Calendar.MINUTE);
00213
if (nowTime < time || today ==
getBackupLastDay())
return;
00214
00215
00216
int count =
getBackupCount();
00217
for (
int i = count-2; i >= 0; i--) {
00218
makeBackupFile(i).renameTo(
makeBackupFile(i+1));
00219 }
00220
00221
00222 OutputStream w =
new FileOutputStream(
makeBackupFile(0));
00223
if (
getBackupFormat().equals(
"xml.gz")) {
00224 w =
new GZIPOutputStream(w);
00225 }
00226 OutputStreamWriter ow =
new OutputStreamWriter(w);
00227 BufferedWriter bw =
new BufferedWriter(ow);
00228
00229
00230
try {
00231 java.sql.Connection conn =
00232
driver.
makeConnection(
this,
"backup", null);
00233 Class c = Class.forName(
backupClass.toString());
00234
Backup b = (
Backup)c.newInstance();
00235 b.
backup(conn, bw);
00236 bw.close();
00237 }
catch (IOException e) {
00238
throw e;
00239 }
catch (Throwable t) {
00240
throw new IOException(t.toString());
00241 }
00242
setBackupLastDay(today);
00243 }
00244
00245 File
makeBackupFile(
int n)
throws IOException {
00246 File bdir =
new File(
getBackupDir());
00247
if (!bdir.exists()) {
00248
if (!bdir.mkdirs()) {
00249
throw new IOException(
"can't create backup directory: " +
00250 bdir.getAbsolutePath());
00251 }
00252 }
00253 String name =
"backup-" + n +
"." +
getBackupFormat();
00254
return new File(bdir, name);
00255 }
00256
00257
00258
00259
00260
00261 public void addIndex(String indexName, String tableName)
00262
throws IOException
00263 {
00264
synchronized (fileLock) {
00265
indexIndex.set(indexName.getBytes(), tableName.getBytes());
00266 }
00267 }
00268
00269
00270
00271
00272
00273 public String
getTableForIndex(String indexName)
throws IOException {
00274
synchronized (fileLock) {
00275 byte[] ret =
indexIndex.get(indexName.getBytes());
00276
if (ret == null)
return null;
00277
return new String(ret);
00278 }
00279 }
00280
00281
00282
00283
00284 public void deleteIndex(String indexName)
throws IOException {
00285
synchronized (fileLock) {
00286
indexIndex.delete(indexName.getBytes());
00287 }
00288 }
00289
00290
00291
00292
00293 void renameIndexedTable(String oldN, String newN)
throws IOException {
00294
synchronized (fileLock) {
00295
BCursor bc =
indexIndex.getCursor(
false);
00296
if (bc != null) {
00297
try {
00298
while (bc.
next()) {
00299 String name =
new String(bc.
getVal());
00300
if (name.equals(oldN)) {
00301 bc.
prev();
00302 bc.
replace(newN.getBytes());
00303 bc.
next();
00304 }
00305 }
00306 } finally {
00307 bc.
release();
00308 }
00309 }
00310 }
00311 }
00312
00313
00314
00315
00316
00317
00318 public long getTableIdentity(String name)
00319
throws IOException, SQLException
00320 {
00321
synchronized (fileLock) {
00322
if (
inMemory) {
00323
Table t = (
Table)
getRelation(name);
00324
return t.
tableIdentity;
00325 }
else {
00326
BCursor tc =
tableIndex.getCursor(
true);
00327
try {
00328
if (tc.
seek(name.getBytes()) &&
00329 tc.
getValLen() >= 16) {
00330
return ByteUtil.getLong(tc.
getValBuf(), 8);
00331 }
else {
00332
throw new SQLException(
"getTableIdentity(" +
00333 name +
"): no table");
00334 }
00335 } finally {
00336 tc.
release();
00337 }
00338 }
00339 }
00340 }
00341
00342
00343
00344
00345
00346
00347 public void updateTableIdentity(String name,
long num)
00348
throws IOException, SQLException
00349 {
00350
synchronized (fileLock) {
00351
if (
inMemory) {
00352
Table t = (
Table)
getRelation(name);
00353 t.
tableIdentity = num;
00354 }
else {
00355
BCursor tc =
tableIndex.getCursor(
true);
00356
try {
00357
if (tc.
seek(name.getBytes())) {
00358
int cnt = tc.
getVal(temp);
00359
ByteUtil.putLong(temp, 8, num);
00360 tc.
replace(temp, 0, cnt);
00361
return;
00362 }
else {
00363
throw new SQLException(
"getTableIdentity(" +
00364 name +
"): no table");
00365 }
00366 } finally {
00367 tc.
release();
00368 }
00369 }
00370 }
00371 }
00372
00373
00374
00375
00376
00377 public java.sql.ResultSet
execute(String sql)
00378
throws SQLException, IOException
00379 {
00380
Connection c =
new Connection(
this,
"__NO_AUTH__", null);
00381
Session session = c.
createSession();
00382
return execute(session, sql);
00383 }
00384
00385
00386
00387
00388 public java.sql.ResultSet
execute(
Session session, String sql)
00389
throws IOException, SQLException
00390 {
00391
SQLParser p =
new SQLParser(session, sql,
true);
00392
Stmt s = null;
00393
try {
00394 s = p.
statement();
00395 }
catch (Throwable t) {
00396
Debug.print(t);
00397 }
00398
00399
if (s == null) {
00400
throw new SQLException(
"Parse error",
"42000");
00401 }
00402 session.doStatement(s);
00403
return session.getResultSet();
00404 }
00405
00406
00407
00408
00409
00410
00411 public Relation getRelation(String name)
00412
throws IOException
00413 {
00414
Relation t = null;
00415
synchronized (fileLock) {
00416 t = (
Relation)
tableMap.get(name);
00417
if (!
inMemory && t == null) {
00418
BCursor tc =
tableIndex.getCursor(
true);
00419
try {
00420
if (tc.
seek(name.getBytes())) {
00421 byte[] d = tc.
getValBuf();
00422 t = (
Relation)getFile().getObject(
ByteUtil.getLong(d, 0));
00423
if (t != null) {
00424
tableMap.put(name, t);
00425 }
00426 }
00427 } finally {
00428 tc.
release();
00429 }
00430 }
00431 }
00432
00433
if (
Trace.bit(0)) {
00434
Debug.println(
"getRelation(" + name +
") = " +
00435 ((t == null) ?
"NOT FOUND" :
"FOUND"));
00436 }
00437
00438
return t;
00439 }
00440
00441
00442
00443
00444 public void addRelation(
Relation table)
00445
throws IOException, SQLException
00446 {
00447
synchronized (fileLock) {
00448 String name = table.
getName();
00449
00450
if (
Trace.bit(0)) {
00451
Debug.println(
"addRelation(" + name +
")");
00452 }
00453
00454
if (
tableMap.get(name) == null) {
00455
tableMap.put(name, table);
00456
if (!
inMemory) {
00457
BCursor tc =
tableIndex.getCursor(
true);
00458
try {
00459 byte[] tkey = name.getBytes();
00460
if (!tc.
seek(name.getBytes())) {
00461
long ref = getFile().putObject(table);
00462
ByteUtil.putLong(temp, 0, ref);
00463
ByteUtil.putLong(temp, 8, 1);
00464 tc.
insert(tkey, tkey.length, temp, 0, 16);
00465 }
00466 } finally {
00467 tc.
release();
00468 }
00469 }
00470 }
else {
00471
throw new SQLException(
"Table/view already exists: " + name,
00472
"42000");
00473 }
00474 }
00475 }
00476
00477
00478
00479
00480 public void removeRelation(String name)
00481
throws IOException, SQLException
00482 {
00483
synchronized (fileLock) {
00484
00485
if (
Trace.bit(0)) {
00486
Debug.println(
"removeRelation(" + name +
")");
00487 }
00488
00489
Relation t = getRelation(name);
00490
if (t == null) {
00491
throw new SQLException(
"No such table/view: " + name,
"42000");
00492 }
00493
removeViewDependencies(name);
00494
tableMap.remove(name);
00495
if (!
inMemory) {
00496
BCursor tc =
tableIndex.getCursor(
true);
00497
try {
00498
if (tc.
seek(name.getBytes())) {
00499 getFile().removeObject(tc.
getValAsLong());
00500 tc.
delete();
00501 }
00502 } finally {
00503 tc.
release();
00504 }
00505 }
00506 }
00507
00508
if (getRelation(name) != null) {
00509
throw new SQLException(
"Relation not removed!!!");
00510 }
00511
00512 }
00513
00514
00515
00516
00517
00518
00519
00520
00521
00522
00523 public void renameRelation(
Relation r, String newN)
throws IOException {
00524
synchronized (fileLock) {
00525 String oldN = r.getName();
00526 r.setName(newN);
00527
tableMap.remove(oldN);
00528
tableMap.put(newN, r);
00529
if (!
inMemory) {
00530
BCursor tc =
tableIndex.getCursor(
true);
00531
try {
00532
if (tc.
seek(oldN.getBytes())) {
00533 byte[] d = tc.
getValBuf();
00534
long ref =
ByteUtil.getLong(d, 0);
00535 tc.
delete();
00536 byte[] nb = newN.getBytes();
00537
if (!tc.
seek(nb)) {
00538 tc.
insert(nb, nb.length, d, 0, 16);
00539 getFile().updateObject(ref, r);
00540 }
00541 }
00542 } finally {
00543 tc.
release();
00544 }
00545 }
00546
if (
true) {
00547
forwardDeps.
rename(oldN, newN,
reverseDeps);
00548
reverseDeps.
rename(oldN, newN,
forwardDeps);
00549 }
00550
if (
true) {
00551 renameIndexedTable(oldN, newN);
00552 }
00553 }
00554 }
00555
00556
00557
00558
00559
00560 public void updateRelation(
Relation table)
throws IOException {
00561
synchronized (fileLock) {
00562
00563
if (
Trace.bit(0)) {
00564
Debug.println(
"updateRelation(" + table.getName() +
")");
00565
00566 }
00567
00568
tableMap.put(table.getName(), table);
00569
if (!
inMemory) {
00570
BCursor tc =
tableIndex.getCursor(
true);
00571
try {
00572
if (tc.
seek(table.getName().getBytes())) {
00573 getFile().updateObject(tc.
getValAsLong(), table);
00574 }
else {
00575
throw new IOException(
"Not found: " + table.getName());
00576 }
00577 } finally {
00578 tc.
release();
00579 }
00580 }
00581 }
00582 }
00583
00584
00585
00586
00587 public void addViewDependency(String base, String view)
00588
throws IOException
00589 {
00590
00591
if (
Trace.bit(0)) {
00592
Debug.println(
"addViewDependency(" + base +
", " + view +
")");
00593 }
00594
00595
00596
synchronized (fileLock) {
00597
forwardDeps.
put(base, view);
00598
reverseDeps.
put(view, base);
00599 }
00600 }
00601
00602
00603
00604
00605 public void checkViewDependency(String base, String view)
00606
throws SQLException, IOException
00607 {
00608
Relation baseR = getRelation(base);
00609
if (baseR == null) {
00610
throw new SQLException(
"Base table not found: " + base,
"42000");
00611 }
00612
if (baseR instanceof
Table) {
00613
Table baseT = (
Table)baseR;
00614
int modifiers = baseT.
getModifiers();
00615
if ((modifiers &
Table.TEMPORARY) != 0) {
00616
throw new SQLException(
"Can't create view of temporary " +
00617
"table " + base,
"42000");
00618 }
00619 }
00620 }
00621
00622
00623
00624
00625 public Enumeration
getViews(String base)
throws IOException {
00626
synchronized (fileLock) {
00627
return forwardDeps.
get(base);
00628 }
00629 }
00630
00631
00632
00633
00634
00635 public Enumeration
getBases(String view)
throws IOException {
00636
synchronized (fileLock) {
00637
return reverseDeps.
get(view);
00638 }
00639 }
00640
00641 public void removeViewDependencies(String view)
00642
throws SQLException, IOException
00643 {
00644
00645
if (
Trace.bit(0)) {
00646
Debug.println(
"removeViewDependencies(" + view +
")");
00647 }
00648
00649
synchronized (fileLock) {
00650 Enumeration views = getViews(view);
00651
if (views.hasMoreElements()) {
00652
throw new SQLException(
"view has dependencies: " + view,
00653
"42000");
00654 }
00655 Enumeration bases = getBases(view);
00656
while (bases.hasMoreElements()) {
00657
forwardDeps.
delete(bases.nextElement().toString(), view);
00658 }
00659 }
00660 }
00661
00662
00663
00664
00665
00666
00667
00668
00669
00670
00671 public Iterator
getRelationNameIterator() throws IOException {
00672
if (
inMemory) {
00673
return tableMap.keySet().iterator();
00674 }
else {
00675
final BCursor tc =
tableIndex.getCursor(
false);
00676
return new Iterator() {
00677
boolean called =
false;
00678
boolean last =
false;
00679
boolean closed =
false;
00680
public boolean hasNext() {
00681
try {
00682
if (!closed && !called) {
00683 last = tc.
next();
00684 called =
true;
00685 }
00686 }
catch (IOException ex) {
00687 last =
false;
00688 }
00689
if (!last && !closed) {
00690 closed =
true;
00691
try {
00692 tc.
release();
00693 }
catch (Throwable t) {
00694
Debug.print(t);
00695 }
00696 }
00697
return last;
00698 }
00699
public Object next() {
00700 Object ret = null;
00701
try {
00702
if (!called && !closed) {
00703 last = tc.
next();
00704 }
00705
if (!last) {
00706
if (!closed) {
00707 closed =
true;
00708
try {
00709 tc.
release();
00710 }
catch (Throwable t) {
00711
Debug.print(t);
00712 }
00713 }
00714 }
else {
00715 ret =
new String(tc.
getKey());
00716 called =
false;
00717 }
00718 }
catch (IOException ex) {
00719 ret =
"<Exception: " + ex +
">";
00720 }
00721
return ret;
00722 }
00723
public void remove() {
00724
try {
00725 tc.
delete();
00726 }
catch (IOException e) {
00727
Debug.print(e);
00728
throw new RuntimeException(
"Error deleting record", e);
00729 }
00730 }
00731 };
00732 }
00733 }
00734
00735
00736
00737
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751
00752
00753
00754
00755
00756 public int addConnection() {
00757
synchronized (
driverLock) {
00758
00759
if (
Trace.bit(8)) {
00760
Debug.println(
"addConnection, count now: " + (
connectionCount+1));
00761 }
00762
00763
return ++
connectionCount;
00764 }
00765 }
00766
00767
00768
00769
00770 public QDriver getDriver() {
00771
return driver;
00772 }
00773
00774
00775
00776
00777
00778 public void removeConnection() {
00779
synchronized (
driverLock) {
00780
if (--
connectionCount == 0 &&
closeCount++ < 1) {
00781
try {
00782 getLog().checkpoint();
00783 }
catch (Throwable e) {
00784 }
00785 }
00786
00787
if (
Trace.bit(8)) {
00788
Debug.println(
"removeConnection, count now: " + (
connectionCount));
00789 }
00790
00791
if (
connectionCount == 0 &&
closeCount == 1) {
00792
driver.
closeDatabase(origFileName);
00793 }
00794 }
00795 }
00796
00797
00798
00799
00800 public int getConnectionCount() {
00801
return connectionCount;
00802 }
00803
00804
00805
00806
00807 public String
getBackupDir() {
00808
return nroot.
getBackupDir();
00809 }
00810
00811
00812
00813
00814 public void setBackupDir(String str)
throws IOException {
00815
nroot.
setBackupDir(str);
00816
flushRoot();
00817 }
00818
00819
00820
00821
00822 public int getBackupCount() {
00823
return nroot.
getBackupCount();
00824 }
00825
00826
00827
00828
00829 public void setBackupCount(
int count)
throws IOException {
00830
nroot.
setBackupCount(count);
00831
flushRoot();
00832 }
00833
00834
00835
00836
00837 public int getBackupDays() {
00838
return nroot.
getBackupDays();
00839 }
00840
00841
00842
00843
00844 public void setBackupDays(
int count)
throws IOException {
00845
nroot.
setBackupDays(count);
00846
flushRoot();
00847 }
00848
00849
00850
00851
00852 public int getBackupLastDay() {
00853
return nroot.
getBackupLastDay();
00854 }
00855
00856
00857
00858
00859 public void setBackupLastDay(
int day)
throws IOException {
00860
nroot.
setBackupLastDay(day);
00861
flushRoot();
00862 }
00863
00864
00865
00866
00867 public int getBackupTime() {
00868
return nroot.
getBackupTime();
00869 }
00870
00871
00872
00873
00874 public void setBackupTime(
int time)
throws IOException {
00875
nroot.
setBackupTime(time);
00876
flushRoot();
00877 }
00878
00879
00880
00881
00882 public String
getBackupFormat() {
00883
return nroot.
getBackupFormat();
00884 }
00885
00886
00887
00888
00889 public void setBackupFormat(String str)
throws IOException {
00890
nroot.
setBackupFormat(str);
00891
flushRoot();
00892 }
00893
00894
00895
00896
00897
00898
00899
00900
00901 public void checkAuth(String user, String passwd)
throws SQLException {
00902
00903 }
00904
00905
00906
00907
00908 public int getPermBlobRefCount(
long blob)
throws IOException {
00909
synchronized (fileLock) {
00910
ByteUtil.putLong(
key, 0, blob);
00911 byte[] val =
blobPermRefCounts.get(
key);
00912
int refcount = val == null ? 0 :
ByteUtil.getInt(val, 0);
00913
return refcount;
00914 }
00915 }
00916
00917
00918
00919
00920
00921
00922 private byte[]
key =
new byte[8];
00923
00924 public int refCountBlob(
long transId,
long blob,
int incr)
00925
throws IOException
00926 {
00927
synchronized (fileLock) {
00928
00929
ByteUtil.putLong(
key, 0, blob);
00930 byte[] val =
blobPermRefCounts.get(
key);
00931
int refcount = val == null ? 0 :
ByteUtil.getInt(val, 0);
00932
int preRefcount = refcount;
00933
00934
00935
if (refcount == 0 && incr == 1) {
00936 val =
new byte[4];
00937
delMorgue(blob);
00938 }
00939 refcount += incr;
00940
if (refcount < 0) {
00941
throw new RuntimeException(
"freePermBlobRef(" + blob +
00942
"), refcount negative");
00943 }
00944
00945
if (refcount <= 0) {
00946
if (preRefcount > 0) {
00947
addMorgue(blob, transId);
00948 }
00949
blobPermRefCounts.delete(
key);
00950 }
else {
00951
00952
ByteUtil.putInt(val, 0, refcount);
00953
blobPermRefCounts.set(
key, val);
00954 }
00955
00956
return refcount;
00957 }
00958 }
00959
00960
00961
00962
00963 public void addMorgue(
long blob,
long transId) {
00964
synchronized (fileLock) {
00965
blobMorgue.put(blob,
new Long(transId));
00966 }
00967 }
00968
00969
00970
00971
00972 public void delMorgue(
long blob) {
00973
synchronized (fileLock) {
00974
blobMorgue.remove(blob);
00975 }
00976 }
00977
00978
00979
00980
00981 public LongIterator enumerateMorgue() {
00982
return blobMorgue.keys();
00983 }
00984
00985
00986
00987
00988
00989
00990
00991 public void checkpointHandler(LongMap activeTransactions)
00992
throws IOException
00993 {
00994
emptyMorgue(activeTransactions);
00995 }
00996
00997
00998
00999
01000
01001 public void emptyMorgue(LongMap activeTransactions)
01002
throws IOException
01003 {
01004
01005
01006
01007
Log saveLog = getLog();
01008 getFile().setLog(null);
01009
try {
01010
synchronized (fileLock) {
01011
LongIterator iter =
enumerateMorgue();
01012
while (iter.hasNext()) {
01013
long blob = iter.
nextLong();
01014
long transId = ((Long)(
blobMorgue.get(blob))).longValue();
01015
if (activeTransactions.get(transId) == null) {
01016
try {
01017 getFile().freeStream(blob);
01018 }
catch (Throwable t) {
01019
Debug.println(
"Error removing blob: " + blob);
01020
Debug.print(t);
01021 }
01022 iter.remove();
01023 }
01024 }
01025 }
01026 } finally {
01027
01028 getFile().setLog(saveLog);
01029 }
01030 }
01031
01032 Session zSession = null;
01033 Connection zConn = null;
01034
01035 final Session getSession(
Transaction t)
throws IOException, SQLException {
01036
if (
zSession == null) {
01037
synchronized (
this) {
01038
if (
zSession == null) {
01039
zConn =
new Connection(
this,
"__SYSTEM", null);
01040
zSession =
zConn.
createSession();
01041 }
01042 }
01043 }
01044
zConn.
transId = t.getTransactionId();
01045
zConn.
trans = t;
01046
return zSession;
01047 }
01048
01049
01050 public void display(PrintWriter w)
throws IOException {
01051 w.println(
"Root:");
01052 w.println(
" blobs: " +
nroot.
getBlobRefCountRoot());
01053 w.println(
" relations: " +
nroot.
getRelationIndexNode());
01054 w.println(
" indexes: " +
nroot.
getIndexIndexNode());
01055 w.println(
" forward deps: " +
nroot.
getForwardDepsNode());
01056 w.println(
" reverse deps: " +
nroot.
getReverseDepsNode());
01057 w.println(
" next trans: " +
nroot.
getNextTransId());
01058
if (
true) {
01059 }
01060
if (
true) {
01061 w.println(
"indexIndex:");
01062
indexIndex.display(w);
01063 w.println(
"tableIndex:");
01064
tableIndex.display(w);
01065 }
01066
if (
true) {
01067 w.println(
"forwardDeps:");
01068
forwardDeps.
display(w);
01069 w.println(
"reverseDeps:");
01070
reverseDeps.
display(w);
01071 }
01072
if (
true) {
01073 }
01074
if (
true) {
01075 }
01076
01077 }
01078
01079
01080
01081
01082
01083 public long putRow(
Session session,
BlockFile f,
01084
Tuple t,
Row row)
01085
throws SQLException, IOException
01086 {
01087
long rowId;
01088
if (
inMemory) {
01089 rowId = f.putObject(row =
new Row(row, t));
01090 }
else {
01091 byte[] buf =
LazyRow.writeRow(session, t, row);
01092 rowId = f.putBytes(buf);
01093 }
01094
01095
if (
Trace.bit(11)) {
01096
Debug.println((f ==
this.file ?
"file" :
"temp") +
"." +
01097 ((t == null) ?
"temp" :
01098 (
"Table[" + t.getName() +
"]")) +
01099
".putRow(" + row +
"): " + rowId);
01100 }
01101
01102
return rowId;
01103 }
01104
01105
01106
01107
01108 public final void putRow(
Session session,
Tuple t,
01109
long rowId,
Row row)
01110
throws SQLException, IOException
01111 {
01112
01113
if (
Trace.bit(11)) {
01114
Debug.println(
"Table[" + t.getName() +
"].putRow(" + row +
")");
01115 }
01116
01117
if (
inMemory) {
01118 getFile().updateObject(rowId,
new Row(row, t));
01119 }
else {
01120 byte[] ret =
LazyRow.writeRow(session, t, row);
01121 getFile().updateBytes(rowId, ret);
01122 }
01123 }
01124
01125 public void getRow(
long rowId,
LazyRow row,
boolean isTemp)
01126
throws IOException, SQLException
01127 {
01128
BlockFile f = isTemp ? getTempFile(
false) : getFile();
01129
if (
inMemory) {
01130
Row r = (
Row)f.
getObject(rowId);
01131
if (r == null) {
01132
throw new IOException(
"No row: " + rowId);
01133 }
01134
if (r.
size() != row.size()) {
01135
01136
Debug.println((isTemp ?
"temp" :
"file") +
".getRow(" +
01137 rowId +
") = " + row);
01138
Debug.println(
"Bad row size in getRow: " + r.
size() +
01139
" vs " + row.size());
01140
01141
throw new IOException(
"Bad row size in getRow: " + r.
size() +
01142
" vs " + row.size());
01143 }
01144
for (
int i = 1; i <= row.size(); i++) {
01145 row.set(i, r.
getItem(i));
01146 }
01147 }
else {
01148 byte[] rowBytes = f.
getBytes(rowId);
01149 row.reset(rowBytes,
this);
01150 }
01151
01152
if (
Trace.bit(11)) {
01153
Debug.println((isTemp ?
"temp" :
"file") +
".getRow(" +
01154 rowId +
") = " + row);
01155 }
01156
01157 }
01158
01159 public void removeRow(
long rowId)
throws IOException {
01160 removeRow(getFile(), rowId);
01161 }
01162
01163 public void removeRow(
BlockFile file,
long rowId)
throws IOException {
01164
if (
inMemory) {
01165 file.removeObject(rowId);
01166 }
else {
01167 file.freeStream(rowId);
01168 }
01169 }
01170
01171 public boolean inMemory() {
01172
return inMemory;
01173 }
01174 }
01175