Clover coverage report -
Coverage timestamp: Sun Nov 1 2009 23:08:24 UTC
file stats: LOC: 405   Methods: 16
NCLOC: 312   Classes: 5
 
 Source file Conditionals Statements Methods TOTAL
DatabaseRebuild.java 0% 0% 0% 0%
coverage
 1    /*
 2    * Licensed to the Apache Software Foundation (ASF) under one or more
 3    * contributor license agreements. See the NOTICE file distributed with
 4    * this work for additional information regarding copyright ownership.
 5    * The ASF licenses this file to You under the Apache License, Version 2.0
 6    * (the "License"); you may not use this file except in compliance with
 7    * the License. You may obtain a copy of the License at
 8    *
 9    * http://www.apache.org/licenses/LICENSE-2.0
 10    *
 11    * Unless required by applicable law or agreed to in writing, software
 12    * distributed under the License is distributed on an "AS IS" BASIS,
 13    * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 14    * See the License for the specific language governing permissions and
 15    * limitations under the License.
 16    *
 17    * $Id: DatabaseRebuild.java 533253 2007-04-27 23:12:12Z vgritsenko $
 18    */
 19   
 20    package org.apache.xindice.tools;
 21   
 22    import org.apache.commons.logging.Log;
 23    import org.apache.commons.logging.LogFactory;
 24    import org.apache.xindice.core.Collection;
 25    import org.apache.xindice.core.DBException;
 26    import org.apache.xindice.core.Database;
 27    import org.apache.xindice.core.data.Key;
 28    import org.apache.xindice.core.data.Value;
 29    import org.apache.xindice.core.filer.BTreeCallback;
 30    import org.apache.xindice.core.filer.BTreeException;
 31    import org.apache.xindice.core.filer.BTreeFiler;
 32    import org.apache.xindice.core.filer.Filer;
 33    import org.apache.xindice.core.filer.HashFiler;
 34    import org.apache.xindice.core.indexer.Indexer;
 35    import org.apache.xindice.util.Configuration;
 36    import org.apache.xindice.util.XindiceException;
 37    import org.apache.xindice.xml.dom.DOMParser;
 38    import org.apache.xindice.server.Xindice;
 39   
 40    import java.io.File;
 41    import java.io.IOException;
 42   
 43    /**
 44    * Command line utility to re-build all btree and hash filer based collections
 45    * of the database, and re-index.
 46    *
 47    * @version $Revision: 533253 $, $Date: 2007-04-27 16:12:12 -0700 (Fri, 27 Apr 2007) $
 48    */
 49    public class DatabaseRebuild {
 50   
 51    private static final Log log = LogFactory.getLog(DatabaseRebuild.class);
 52   
 53    private static final int CMD_ALL = 0;
 54    private static final int CMD_COPY = 1;
 55    private static final int CMD_INDEX = 2;
 56   
 57    private static final char NOT_RAN = '_';
 58    private static final char SUCCESS = '*';
 59    private static final char ERROR = '!';
 60   
 61   
 62  0 public static void main(String[] args) throws Exception {
 63  0 if (args.length < 2 || args[1] == null || args[1].length() == 0 ||
 64    !("copy".equals(args[0]) || "index".equals(args[0]) || "rebuild".equals(args[0]))) {
 65  0 usage();
 66  0 System.exit(1);
 67    }
 68   
 69  0 int command;
 70  0 if ("copy".equals(args[0])) {
 71  0 command = CMD_COPY;
 72  0 } else if ("index".equals(args[0])) {
 73  0 command = CMD_INDEX;
 74    } else {
 75  0 command = CMD_ALL;
 76    }
 77   
 78  0 File location = new File(args[1]);
 79  0 String path = location.getAbsolutePath();
 80  0 String name = location.getName();
 81   
 82  0 if ("".equals(name) || !location.exists() || !location.isDirectory()) {
 83  0 System.out.println("Database path must point to existing database directory");
 84  0 System.exit(1);
 85    }
 86   
 87    // create minimal database configuration instead of trying to locate system.xml
 88  0 String config = "<root-collection dbroot='" + path + "/' name='" + name + "'/>";
 89  0 Database db = new Database();
 90   
 91  0 boolean success = true;
 92  0 try {
 93  0 System.out.println("Processing database " + path);
 94  0 System.out.println();
 95  0 System.out.println("DI\tCollection name");
 96   
 97  0 db.setConfig(new Configuration(DOMParser.toDocument(config)));
 98   
 99  0 if (log.isInfoEnabled()) {
 100  0 log.info("Rebuilding collections...");
 101    }
 102  0 success = processCollection(db, command);
 103    } finally {
 104  0 db.close();
 105   
 106  0 System.out.println();
 107  0 System.out.println("Legend:");
 108  0 System.out.println(" D Data file");
 109  0 System.out.println(" I Index files");
 110  0 System.out.println(" _ File was skipped");
 111  0 System.out.println(" * File was processed successfuly");
 112  0 System.out.println(" ! File processing failed");
 113   
 114  0 System.out.println();
 115  0 if (success) {
 116  0 System.out.println("Rebuilding database was successfull.");
 117    } else {
 118  0 System.out.println("Rebuilding database failed. Please check logs for more detail.");
 119    }
 120   
 121  0 System.exit(success ? 0 : 2);
 122    }
 123   
 124    }
 125   
 126  0 private static void usage() {
 127  0 System.out.println("Xindice " + Xindice.Version + " Database Rebuild Utility");
 128  0 System.out.println("Usage:");
 129  0 System.out.println(" xindice_rebuild copy <db location>");
 130  0 System.out.println(" xindice_rebuild index <db location>");
 131  0 System.out.println(" xindice_rebuild rebuild <db location>");
 132  0 System.out.println();
 133  0 System.out.println("DB Location should point to the directory containing Xindice database files.");
 134  0 System.out.println();
 135  0 System.out.println("Important: Shutdown and backup database before proceeding!");
 136  0 System.out.println();
 137    }
 138   
 139  0 private static boolean processCollection(Collection col, int command) {
 140  0 String name = col.getCanonicalName();
 141  0 boolean status;
 142   
 143  0 try {
 144  0 if (log.isInfoEnabled()) {
 145  0 log.info("Processing collection " + name);
 146    }
 147   
 148  0 char copy = NOT_RAN;
 149  0 char index = NOT_RAN;
 150  0 switch (command) {
 151  0 case CMD_COPY:
 152  0 status = rebuildCollection(col);
 153  0 copy = status ? SUCCESS : ERROR;
 154  0 break;
 155   
 156  0 case CMD_INDEX:
 157  0 status = rebuildIndex(col);
 158  0 index = status ? SUCCESS : ERROR;
 159  0 break;
 160  0 default:
 161  0 status = rebuildCollection(col);
 162  0 copy = status ? SUCCESS : ERROR;
 163  0 if (status) {
 164  0 status = rebuildIndex(col);
 165  0 index = status ? SUCCESS : ERROR;
 166    }
 167  0 break;
 168    }
 169   
 170  0 System.out.println(String.valueOf(copy) + String.valueOf(index) + "\t" + name);
 171   
 172  0 String[] colNames = col.listCollections();
 173  0 for (int i = 0; i < colNames.length; i++) {
 174  0 boolean result = processCollection(col.getCollection(colNames[i]), command);
 175  0 status = status && result;
 176    }
 177    } catch (DBException e) {
 178  0 log.error("Got an exception when processing collection " + name, e);
 179   
 180  0 return false;
 181    }
 182   
 183  0 return status;
 184    }
 185   
 186  0 private static boolean rebuildCollection(Collection col) {
 187  0 String canonicalName = col.getCanonicalName();
 188   
 189    // close collection's filer
 190  0 try {
 191  0 if (col.getFiler() != null) {
 192  0 col.getFiler().close();
 193    }
 194    } catch (DBException e) {
 195  0 log.error("Could not close filer for collection " + canonicalName, e);
 196  0 return false;
 197    }
 198   
 199    // prepare
 200  0 Filer itsFiler = col.getFiler();
 201  0 FilerCopy oldFiler;
 202  0 FilerCopy newFiler;
 203  0 if (itsFiler == null) {
 204  0 if (log.isInfoEnabled()) {
 205  0 log.info("Collection " + col.getCanonicalName() + " has no filer. Skipping...");
 206    }
 207   
 208  0 return true;
 209  0 } if (itsFiler instanceof BTreeFiler) {
 210  0 oldFiler = new BTreeCopy();
 211  0 newFiler = new BTreeCopy();
 212  0 } else if (itsFiler instanceof HashFiler) {
 213  0 oldFiler = new HashCopy();
 214  0 newFiler = new HashCopy();
 215    } else {
 216  0 if (log.isInfoEnabled()) {
 217  0 log.info("Collection " + col.getCanonicalName() + " has unrecognized filer '" + itsFiler.getClass().getName() + "'. Skipping...");
 218    }
 219   
 220  0 return true;
 221    }
 222   
 223  0 String oldFileName;
 224  0 String newFileName;
 225  0 try {
 226  0 oldFiler.setLocation(col.getCollectionRoot(), col.getName());
 227  0 oldFiler.setConfig(col.getFiler().getConfig());
 228  0 oldFileName = oldFiler.getFilerFile().getAbsolutePath();
 229  0 if (!oldFiler.exists()) {
 230  0 log.error("Filer for " + oldFileName + " does not exists");
 231  0 return false;
 232    }
 233   
 234  0 newFiler.setLocation(col.getCollectionRoot(), col.getName() + ".rebuild");
 235  0 newFiler.setConfig(col.getFiler().getConfig());
 236  0 newFileName = newFiler.getFilerFile().getAbsolutePath();
 237  0 if (newFiler.exists()) {
 238  0 log.error("Filer for " + newFileName + " already exists");
 239  0 return false;
 240    }
 241    } catch (XindiceException e) {
 242  0 log.error("Got an exception when preparing to rebuild " + canonicalName, e);
 243  0 return false;
 244    }
 245   
 246    // copy
 247  0 if (!copy(oldFiler, newFiler, canonicalName)) {
 248  0 newFiler.deleteFile();
 249  0 return false;
 250    }
 251   
 252  0 oldFiler.deleteFile();
 253  0 if (!newFiler.getFilerFile().renameTo(oldFiler.getFilerFile())) {
 254  0 log.error("Could not rename successfully rebuilt file " + newFileName + " to " + oldFileName);
 255  0 return false;
 256    }
 257   
 258  0 try {
 259  0 col.getFiler().open();
 260    } catch (DBException e) {
 261  0 log.error("Could not open new file " + oldFileName, e);
 262  0 return false;
 263    }
 264   
 265  0 return true;
 266    }
 267   
 268  0 private static boolean copy(FilerCopy oldFiler, FilerCopy newFiler, String canonicalName) {
 269  0 try {
 270  0 newFiler.create();
 271  0 oldFiler.open();
 272  0 newFiler.open();
 273  0 oldFiler.copy(newFiler);
 274    } catch (Exception e) {
 275  0 log.error("Error copying collection " + canonicalName, e);
 276  0 return false;
 277    } finally {
 278  0 try {
 279  0 oldFiler.close();
 280    } catch (DBException e) {
 281  0 if (log.isWarnEnabled()) log.warn(e);
 282    }
 283  0 try {
 284  0 newFiler.close();
 285    } catch (DBException e) {
 286  0 if (log.isWarnEnabled()) log.warn(e);
 287    }
 288    }
 289   
 290  0 return true;
 291    }
 292   
 293  0 private static boolean rebuildIndex(Collection col) {
 294  0 if (col.getFiler() == null) {
 295  0 return true;
 296    }
 297   
 298  0 try {
 299  0 String[] list = col.listIndexers();
 300  0 for (int i = 0; i < list.length; i++) {
 301  0 Indexer idx = col.getIndexer(list[i]);
 302  0 Configuration idxConf = idx.getConfig();
 303  0 if (log.isInfoEnabled()) {
 304  0 log.info("Rebuilding index " + list[i] + " for collection " + col.getCanonicalName());
 305    }
 306  0 col.dropIndexer(idx);
 307  0 col.createIndexer(idxConf);
 308    }
 309    } catch (DBException e) {
 310  0 log.error("Could not rebuild index for collection " + col.getCanonicalName(), e);
 311  0 return false;
 312    }
 313   
 314  0 return true;
 315    }
 316   
 317    private interface FilerCopy extends Filer {
 318    public Value getValue(long pointer) throws IOException;
 319   
 320    public void copy(Filer newFiler) throws IOException, DBException;
 321   
 322    public boolean deleteFile();
 323   
 324    public File getFilerFile();
 325    }
 326   
 327    private static class BTreeCopy extends BTreeFiler implements FilerCopy {
 328  0 public Value getValue(long pointer) throws IOException {
 329  0 return super.readValue(pointer);
 330    }
 331   
 332  0 public void copy(Filer newFiler) throws IOException, BTreeException {
 333  0 query(null, new CopyCallback(this, newFiler));
 334    }
 335   
 336  0 public boolean deleteFile() {
 337  0 return getFile().delete();
 338    }
 339   
 340  0 public File getFilerFile() {
 341  0 return getFile();
 342    }
 343    }
 344   
 345    private static class HashCopy extends HashFiler implements FilerCopy {
 346  0 public Value getValue(long pointer) throws IOException {
 347  0 return super.readValue(pointer);
 348    }
 349   
 350  0 public void copy(Filer newFiler) throws IOException, DBException {
 351  0 long hashSize = getFileHeader().getPageCount();
 352   
 353  0 for (long i = 0; i < hashSize; i++) {
 354  0 Page page = getPage(i);
 355   
 356  0 while (true) {
 357  0 HashPageHeader ph = (HashPageHeader) page.getPageHeader();
 358   
 359  0 if (ph.getStatus() == RECORD) {
 360  0 Value value = readValue(page);
 361  0 newFiler.writeRecord(page.getKey(), value);
 362   
 363  0 long next = ph.getNextCollision();
 364  0 if (next != NO_PAGE) {
 365  0 page = getPage(ph.getNextCollision());
 366    } else {
 367  0 break;
 368    }
 369    } else {
 370  0 break;
 371    }
 372    }
 373    }
 374    }
 375   
 376  0 public boolean deleteFile() {
 377  0 return getFile().delete();
 378    }
 379   
 380  0 public File getFilerFile() {
 381  0 return getFile();
 382    }
 383    }
 384   
 385    private static class CopyCallback implements BTreeCallback {
 386    private BTreeCopy filer;
 387    private Filer newFiler;
 388   
 389  0 public CopyCallback(BTreeCopy filer, Filer newFiler) {
 390  0 this.filer = filer;
 391  0 this.newFiler = newFiler;
 392    }
 393   
 394  0 public boolean indexInfo(Value value, long pointer) {
 395  0 try {
 396  0 Value v = filer.getValue(pointer);
 397  0 newFiler.writeRecord(new Key(value), v);
 398    } catch (Exception e) {
 399  0 log.error(e);
 400    }
 401   
 402  0 return true;
 403    }
 404    }
 405    }