--- java/src/org/apache/xindice/tools/DatabaseRebuild.java (revision 518809) +++ java/src/org/apache/xindice/tools/DatabaseRebuild.java (working copy) @@ -22,6 +22,7 @@ import org.apache.xindice.xml.dom.DOMParser; import org.apache.xindice.core.filer.BTreeFiler; import org.apache.xindice.core.filer.BTreeCallback; +import org.apache.xindice.core.filer.BTreeException; import org.apache.xindice.core.data.Value; import org.apache.xindice.core.data.Key; import org.apache.xindice.core.Database; @@ -29,7 +30,8 @@ import org.apache.xindice.core.DBException; import org.apache.xindice.core.indexer.Indexer; import org.apache.xindice.util.Configuration; -import org.apache.xindice.util.XindiceException; +import org.apache.commons.logging.Log; +import org.apache.commons.logging.LogFactory; import java.io.File; import java.io.IOException; @@ -41,152 +43,233 @@ */ public class DatabaseRebuild { + private static final int CMD_ALL = 0; private static final int CMD_COPY = 1; private static final int CMD_INDEX = 2; - private static Database db; - private static String path; - private static boolean removeBackupFiles; - private static int command; + private static final char NOT_RAN = '_'; + private static final char SUCCESS = '*'; + private static final char ERROR = '!'; + private static final Log log = LogFactory.getLog(DatabaseRebuild.class); public static void main(String[] args) throws Exception { - if (args.length < 2 || !("copy".equals(args[0]) || "index".equals(args[0])) || - args[1] == null || args[1].length() == 0) { + if (args.length < 2 || args[1] == null || args[1].length() == 0 || + !("copy".equals(args[0]) || "index".equals(args[0]) || "rebuild".equals(args[0]))) { usage(); - return; + System.exit(1); } - command = "copy".equals(args[0]) ? CMD_COPY : CMD_INDEX; + int command; + if ("copy".equals(args[0])) { + command = CMD_COPY; + } else if ("index".equals(args[0])) { + command = CMD_INDEX; + } else { + command = CMD_ALL; + } + String dbLocation = args[1]; - if (args.length > 2 && args[2].equals("--remove")) { - removeBackupFiles = true; + + File location = new File(dbLocation); + dbLocation = location.getAbsolutePath(); + String name = location.getName(); + + if ("".equals(name) || !location.exists() || !location.isDirectory()) { + System.out.println("Database path must point to existing database directory"); + System.exit(1); } - String config = ""; - db = new Database(); + // create minimal database configuration instead of trying to locate system.xml + String config = ""; + Database db = new Database(); + boolean status = true; try { + System.out.println(); + System.out.println("CI\tCollection name"); + db.setConfig(new Configuration(DOMParser.toDocument(config))); - path = db.getCollectionRoot().getPath(); - processChildCollections("/"); + if (log.isInfoEnabled()) { + log.info("Rebuilding collections..."); + } + status = processCollection(db, command); } finally { db.close(); + + System.out.println(); + if (status) { + System.out.println("Rebuilding database was successfull"); + } else { + System.out.println("Rebuilding database failed. Please check logs for more detail"); + } + + System.exit(status ? 0 : 2); } + } private static void usage() { System.out.println("Commands:"); - System.out.println("copy [--remove]"); - System.out.println("index "); + System.out.println("copy -v"); + System.out.println("index -v"); + System.out.println("rebuild -v"); } - private static void processChildCollections(String colRoot) { - System.out.println("Getting child collections for " + colRoot); + private static boolean processCollection(Collection col, int command) { + String name = col.getCanonicalName(); + boolean status; + try { - // Get a Collection reference - Collection col = db.getCollection(colRoot); - if (col == null) { - System.out.println("Error fetching collection '" + colRoot + "'"); - return; + if (log.isInfoEnabled()) { + log.info("Processing collection " + name); } - processCollection(col, colRoot); + char copy = NOT_RAN; + char index = NOT_RAN; + switch (command) { + case CMD_COPY: + status = rebuildCollection(col); + copy = status ? SUCCESS : ERROR; + break; + case CMD_INDEX: + status = rebuildIndex(col); + index = status ? SUCCESS : ERROR; + break; + default: + status = rebuildCollection(col); + copy = status ? SUCCESS : ERROR; + if (status) { + status = rebuildIndex(col); + index = status ? SUCCESS : ERROR; + } + break; + } + + System.out.println(Character.toString(copy) + Character.toString(index) + "\t" + name); + String[] colNames = col.listCollections(); for (int i = 0; i < colNames.length; i++) { - processChildCollections(colRoot + colNames[i] + "/"); + boolean result = processCollection(col.getCollection(colNames[i]), command); + status = status && result; } - } catch (Exception e) { - System.out.println("Got an excefption when processing collection: " + colRoot); - e.printStackTrace(); + } catch (DBException e) { + log.error("Got an exception when processing collection " + name, e); + + return false; } + + return status; } - private static void processCollection(Collection col, String location) throws XindiceException, IOException { - switch (command) { - case CMD_INDEX: - rebuildIndex(col); - break; + private static boolean rebuildCollection(Collection col) { + String canonicalName = col.getCanonicalName(); - case CMD_COPY: - rebuildCollection(col, location, col.getName()); - break; + if (!(col.getFiler() instanceof BTreeFiler)) { + if (log.isInfoEnabled()) { + log.info("Filer for collection " + canonicalName + " is not BTreeFiler. Skipping..."); + } + return true; } - } - private static void rebuildCollection(Collection col, String location, String name) throws XindiceException, IOException { - if (!(col.getFiler() instanceof BTreeFiler)) { - System.out.println("Filer for collection " + location + " is not BTreeFiler. Skipping..."); - return; + // close collection's filer + try { + col.getFiler().close(); + } catch (DBException e) { + log.error("Could not close filer for collection " + canonicalName, e); + return false; } - // close collection and its filer - col.close(); - - System.out.println("Processing collection " + location); - - File root = new File(path + location); - - // backup - String fileName = path + location + "/" + name; - // FIXME What if copy fails. It's probably a better idea to first make a copy, - // and rename after that? - new File(fileName + ".tbl").renameTo(new File(fileName + ".old.tbl")); - // prepare - BTreeCopy filer = new BTreeCopy(); - filer.setLocation(root, name + ".old"); - filer.setConfig(col.getFiler().getConfig()); - if (!filer.exists()) { - System.out.println("Filer for " + fileName + ".old.tbl does not exists"); - return; + BTreeCopy oldFiler = new BTreeCopy(); + oldFiler.setLocation(col.getCollectionRoot(), col.getName()); + oldFiler.setConfig(col.getFiler().getConfig()); + String oldFileName = oldFiler.getFilerFile().getAbsolutePath(); + if (!oldFiler.exists()) { + log.error("Filer for " + oldFileName + " does not exists"); + return false; } - BTreeFiler newFiler = new BTreeFiler(); - newFiler.setLocation(root, name); + BTreeCopy newFiler = new BTreeCopy(); + newFiler.setLocation(col.getCollectionRoot(), col.getName() + ".rebuild"); newFiler.setConfig(col.getFiler().getConfig()); + String newFileName = newFiler.getFilerFile().getAbsolutePath(); if (newFiler.exists()) { - System.out.println("Filer for " + fileName + ".tbl already exists"); - return; + log.error("Filer for " + newFileName + " already exists"); + return false; } // copy - newFiler.create(); + if (!copy(oldFiler, newFiler, canonicalName)) { + newFiler.deleteFile(); + return false; + } + + oldFiler.deleteFile(); + if (!newFiler.getFilerFile().renameTo(oldFiler.getFilerFile())) { + log.error("Could not rename successfully rebuilt file " + newFileName + " to " + oldFileName); + return false; + } + try { - filer.open(); + col.getFiler().open(); + } catch (DBException e) { + log.error("Could not open new file " + oldFileName, e); + return false; + } + + return true; + } + + private static boolean copy(BTreeCopy oldFiler, BTreeCopy newFiler, String canonicalName) { + try { + newFiler.create(); + oldFiler.open(); newFiler.open(); - - filer.copy(newFiler); - if (removeBackupFiles) { - filer.deleteFile(); - } + oldFiler.copy(newFiler); + } catch (Exception e) { + log.error("Error copying collection " + canonicalName, e); + return false; } finally { try { - filer.close(); - } catch (Exception e) { - e.printStackTrace(); + oldFiler.close(); + } catch (DBException e) { + if (log.isWarnEnabled()) log.warn(e); } try { newFiler.close(); - } catch (Exception e) { - e.printStackTrace(); + } catch (DBException e) { + if (log.isWarnEnabled()) log.warn(e); } } + + return true; } - private static void rebuildIndex(Collection col) throws DBException { - if (col.getFiler() != null) { + private static boolean rebuildIndex(Collection col) { + if (col.getFiler() == null) { + return true; + } + + try { String[] list = col.listIndexers(); for (int i = 0; i < list.length; i++) { Indexer idx = col.getIndexer(list[i]); Configuration idxConf = idx.getConfig(); - System.out.println("Rebuilding index " + list[i] + " for collection " + col.getName()); + if (log.isInfoEnabled()) { + log.info("Rebuilding index " + list[i] + " for collection " + col.getCanonicalName()); + } col.dropIndexer(idx); col.createIndexer(idxConf); } + } catch (DBException e) { + log.error("Could not rebuild index for collection " + col.getCanonicalName(), e); + return false; } + + return true; } private static class BTreeCopy extends BTreeFiler { @@ -194,13 +277,17 @@ return super.readValue(pointer); } - private void copy(BTreeFiler newFiler) throws XindiceException, IOException { + private void copy(BTreeFiler newFiler) throws IOException, BTreeException { query(null, new CopyCallback(this, newFiler)); } private boolean deleteFile() { return getFile().delete(); } + + private File getFilerFile() { + return getFile(); + } } private static class CopyCallback implements BTreeCallback {