1 30 31 32 package org.hsqldb.persist; 33 34 import java.io.BufferedOutputStream ; 35 import java.io.IOException ; 36 import java.io.OutputStream ; 37 38 import org.hsqldb.Database; 39 import org.hsqldb.HsqlException; 40 import org.hsqldb.Session; 41 import org.hsqldb.Table; 42 import org.hsqldb.Trace; 43 import org.hsqldb.index.RowIterator; 44 import org.hsqldb.lib.DoubleIntIndex; 45 import org.hsqldb.lib.HsqlArrayList; 46 import org.hsqldb.lib.StopWatch; 47 import org.hsqldb.lib.Storage; 48 import org.hsqldb.rowio.RowInputInterface; 49 import org.hsqldb.rowio.RowOutputBinary; 50 51 53 67 final class DataFileDefrag { 68 69 BufferedOutputStream fileStreamOut; 70 long fileOffset; 71 StopWatch stopw = new StopWatch(); 72 String filename; 73 int[][] rootsList; 74 Database database; 75 DataFileCache cache; 76 int scale; 77 DoubleIntIndex transactionRowLookup; 78 79 DataFileDefrag(Database db, DataFileCache cache, String filename) { 80 81 this.database = db; 82 this.cache = cache; 83 this.scale = cache.cacheFileScale; 84 this.filename = filename; 85 } 86 87 void process() throws HsqlException, IOException { 88 89 boolean complete = false; 90 91 Trace.printSystemOut("Defrag Transfer begins"); 92 93 transactionRowLookup = database.txManager.getTransactionIDList(); 94 95 HsqlArrayList allTables = database.schemaManager.getAllTables(); 96 97 rootsList = new int[allTables.size()][]; 98 99 Storage dest = null; 100 101 try { 102 OutputStream fos = 103 database.getFileAccess().openOutputStreamElement(filename 104 + ".new"); 105 106 fileStreamOut = new BufferedOutputStream (fos, 1 << 12); 107 108 for (int i = 0; i < DataFileCache.INITIAL_FREE_POS; i++) { 109 fileStreamOut.write(0); 110 } 111 112 fileOffset = DataFileCache.INITIAL_FREE_POS; 113 114 for (int i = 0, tSize = allTables.size(); i < tSize; i++) { 115 Table t = (Table) allTables.get(i); 116 117 if (t.getTableType() == Table.CACHED_TABLE) { 118 int[] rootsArray = writeTableToDataFile(t); 119 120 rootsList[i] = rootsArray; 121 } else { 122 rootsList[i] = null; 123 } 124 125 Trace.printSystemOut(t.getName().name + " complete"); 126 } 127 128 writeTransactionRows(); 129 fileStreamOut.close(); 130 131 fileStreamOut = null; 132 133 dest = ScaledRAFile.newScaledRAFile( 135 database, filename 136 + ".new", false, ScaledRAFile.DATA_FILE_RAF, database 137 .getURLProperties().getProperty( 138 "storage_class_name"), database.getURLProperties() 139 .getProperty("storage_key")); 140 141 dest.seek(DataFileCache.LONG_FREE_POS_POS); 142 dest.writeLong(fileOffset); 143 dest.close(); 144 145 dest = null; 146 147 for (int i = 0, size = rootsList.length; i < size; i++) { 148 int[] roots = rootsList[i]; 149 150 if (roots != null) { 151 Trace.printSystemOut( 152 org.hsqldb.lib.StringUtil.getList(roots, ",", "")); 153 } 154 } 155 156 complete = true; 157 } catch (IOException e) { 158 throw Trace.error(Trace.FILE_IO_ERROR, filename + ".new"); 159 } catch (OutOfMemoryError e) { 160 throw Trace.error(Trace.OUT_OF_MEMORY); 161 } finally { 162 if (fileStreamOut != null) { 163 fileStreamOut.close(); 164 } 165 166 if (dest != null) { 167 dest.close(); 168 } 169 170 if (!complete) { 171 database.getFileAccess().removeElement(filename + ".new"); 172 } 173 } 174 175 } 177 178 181 void updateTableIndexRoots() throws HsqlException { 182 183 HsqlArrayList allTables = database.schemaManager.getAllTables(); 184 185 for (int i = 0, size = allTables.size(); i < size; i++) { 186 Table t = (Table) allTables.get(i); 187 188 if (t.getTableType() == Table.CACHED_TABLE) { 189 int[] rootsArray = rootsList[i]; 190 191 t.setIndexRoots(rootsArray); 192 } 193 } 194 } 195 196 199 void updateTransactionRowIDs() throws HsqlException { 200 database.txManager.convertTransactionIDs(transactionRowLookup); 201 } 202 203 int[] writeTableToDataFile(Table table) 204 throws IOException , HsqlException { 205 206 Session session = database.getSessionManager().getSysSession(); 207 RowOutputBinary rowOut = new RowOutputBinary(); 208 DoubleIntIndex pointerLookup = 209 new DoubleIntIndex(table.getPrimaryIndex().sizeEstimate(), false); 210 int[] rootsArray = table.getIndexRootsArray(); 211 long pos = fileOffset; 212 int count = 0; 213 214 pointerLookup.setKeysSearchTarget(); 215 Trace.printSystemOut("lookup begins: " + stopw.elapsedTime()); 216 217 RowIterator it = table.rowIterator(session); 218 219 for (; it.hasNext(); count++) { 220 CachedObject row = (CachedObject) it.next(); 221 222 pointerLookup.addUnsorted(row.getPos(), (int) (pos / scale)); 223 224 if (count % 50000 == 0) { 225 Trace.printSystemOut("pointer pair for row " + count + " " 226 + row.getPos() + " " + pos); 227 } 228 229 pos += row.getStorageSize(); 230 } 231 232 Trace.printSystemOut(table.getName().name + " list done ", 233 stopw.elapsedTime()); 234 235 count = 0; 236 it = table.rowIterator(session); 237 238 for (; it.hasNext(); count++) { 239 CachedObject row = it.next(); 240 241 rowOut.reset(); 242 row.write(rowOut, pointerLookup); 243 fileStreamOut.write(rowOut.getOutputStream().getBuffer(), 0, 244 rowOut.size()); 245 246 fileOffset += row.getStorageSize(); 247 248 if ((count) % 50000 == 0) { 249 Trace.printSystemOut(count + " rows " + stopw.elapsedTime()); 250 } 251 } 252 253 for (int i = 0; i < rootsArray.length; i++) { 254 if (rootsArray[i] == -1) { 255 continue; 256 } 257 258 int lookupIndex = 259 pointerLookup.findFirstEqualKeyIndex(rootsArray[i]); 260 261 if (lookupIndex == -1) { 262 throw Trace.error(Trace.DATA_FILE_ERROR); 263 } 264 265 rootsArray[i] = pointerLookup.getValue(lookupIndex); 266 } 267 268 setTransactionRowLookups(pointerLookup); 269 Trace.printSystemOut(table.getName().name + " : table converted"); 270 271 return rootsArray; 272 } 273 274 void setTransactionRowLookups(DoubleIntIndex pointerLookup) { 275 276 for (int i = 0, size = transactionRowLookup.size(); i < size; i++) { 277 int key = transactionRowLookup.getKey(i); 278 int lookupIndex = pointerLookup.findFirstEqualKeyIndex(key); 279 280 if (lookupIndex != -1) { 281 transactionRowLookup.setValue( 282 i, pointerLookup.getValue(lookupIndex)); 283 } 284 } 285 } 286 287 void writeTransactionRows() { 288 289 for (int i = 0, size = transactionRowLookup.size(); i < size; i++) { 290 if (transactionRowLookup.getValue(i) != 0) { 291 continue; 292 } 293 294 int key = transactionRowLookup.getKey(i); 295 296 try { 297 transactionRowLookup.setValue(i, (int) (fileOffset / scale)); 298 299 RowInputInterface rowIn = cache.readObject(key); 300 301 fileStreamOut.write(rowIn.getBuffer(), 0, rowIn.getSize()); 302 303 fileOffset += rowIn.getSize(); 304 } catch (IOException e) {} 305 } 306 } 307 } 308 | Popular Tags |