001: // You can redistribute this software and/or modify it under the terms of
002: // the Ozone Library License version 1 published by ozone-db.org.
003: //
004: // The original code and portions created by SMB are
005: // Copyright (C) 1997-@year@ by SMB GmbH. All rights reserved.
006: //
007: // $Id: BackupRestore.java,v 1.2 2002/06/08 00:49:39 mediumnet Exp $
008:
009: package org.ozoneDB.core.admin;
010:
011: import java.io.*;
012:
013: import org.xml.sax.*;
014: import org.xml.sax.helpers.*;
015:
016: import org.apache.xml.serialize.*;
017:
018: import org.ozoneDB.*;
019: import org.ozoneDB.util.*;
020: import org.ozoneDB.core.*;
021: import org.ozoneDB.core.xml.*;
022: import org.ozoneDB.xml.util.*;
023: import org.ozoneDB.DxLib.*;
024:
025: /**
026: * This class handles all backup/restore related operations of the ozone admin
027: * system.<p>
028: *
029: * Note: The backup/restore does not use the object specific object to XML
030: * mapping. The backup always uses the standard mapping defined by {@link
031: * org.ozoneDB.core.xml.Object2XML}.
032: *
033: * @version $Revision: 1.2 $ $Date: 2002/06/08 00:49:39 $
034: * @author <a href="http://www.smb-tec.com">SMB</a>
035: * @see Admin
036: */
037: public class BackupRestore implements XML2ObjectDelegate {
038:
039: protected final static String TMP_FILE_NAME = "oids.tmp";
040:
041: protected final static String BACKUP_ELEMENT_NAME = "ozone-database-backup";
042:
043: protected transient Env env;
044:
045: protected transient SAXChunkProducer backupProducer;
046:
047: protected transient DataInputStream backupIn;
048:
049: protected transient SAXChunkConsumer restoreConsumer;
050:
051: protected transient int idcount;
052:
053: public BackupRestore(Env _env) {
054: env = _env;
055: }
056:
057: public void beginRestore() throws Exception {
058: env.logWriter.newEntry(this , "beginRestore()...",
059: LogWriter.INFO);
060:
061: if (restoreConsumer != null) {
062: throw new IllegalStateException(
063: "There is a restore process already in progress.");
064: }
065: XML2ObjectContentHandler restoreHandler = new XML2ObjectContentHandler(
066: this );
067: restoreConsumer = new SAXChunkConsumer(restoreHandler);
068: }
069:
070: public void processRestoreChunk(byte[] chunk) throws Exception {
071: if (restoreConsumer == null) {
072: throw new IllegalStateException(
073: "Start the restore process first.");
074: }
075: if (chunk == null) {
076: restoreConsumer = null;
077: } else {
078: System.out.println("");
079: env.logWriter.newEntry(this , "processRestoreChunk(): size="
080: + chunk.length, LogWriter.INFO);
081: restoreConsumer.processChunk(chunk);
082: }
083: }
084:
085: /**
086: * This method is inherited from XML2ObjectDelegate. It is called when an
087: * entire object is re-constructed from the XML stream.
088: */
089: public void handleObject(ObjElement element) {
090: System.out.print('.');
091:
092: OzoneCompatible obj = (OzoneCompatible) element.getObject();
093: ObjectID id = new ObjectID(Long.parseLong((String) element
094: .getOzoneObjectId()));
095: String name = (String) element.getOzoneObjectName();
096:
097: env.logWriter.newEntry(this , "handleObject(): "
098: + element.getClassName() + ": oid=" + id + ", target="
099: + obj, LogWriter.DEBUG3);
100:
101: try {
102: ObjectContainer container = env.transactionManager
103: .currentTA()
104: .createObjectAndPin(null, OzoneInterface.Public,
105: name, null, null, id);
106:
107: try {
108: container.setTarget(obj);
109: } finally {
110: container.unpin();
111: }
112: } catch (Exception e) {
113: throw new RuntimeException(e.toString());
114: }
115: }
116:
117: public void beginBackup() throws Exception {
118: if (backupIn != null) {
119: throw new IllegalStateException(
120: "There is a backup process already in progress.");
121: }
122:
123: backupProducer = new SAXChunkProducer(
124: (SAXChunkProducerDelegate) null);
125: backupProducer.startDocument();
126: backupProducer.startElement("", BACKUP_ELEMENT_NAME,
127: BACKUP_ELEMENT_NAME, new AttributesImpl());
128:
129: env.logWriter.newEntry(this , "preparing list of object IDs...",
130: LogWriter.INFO);
131:
132: idcount = 0;
133: DataOutputStream out = new DataOutputStream(
134: new BufferedOutputStream(new FileOutputStream(env.dir
135: + TMP_FILE_NAME), 4096));
136: DxIterator backupIt = env.storeManager.objectIDIterator();
137: while (backupIt.next() != null) {
138: out.writeLong(((ObjectID) backupIt.key()).value());
139: idcount++;
140: }
141: out.close();
142:
143: env.logWriter.newEntry(this ,
144: "preparing list of object IDs... ready. (" + idcount
145: + " IDs)", LogWriter.INFO);
146: idcount = 0;
147:
148: backupIn = new DataInputStream(new BufferedInputStream(
149: new FileInputStream(env.dir + TMP_FILE_NAME), 4096));
150: }
151:
152: private ObjectID nextBackupID() throws Exception {
153: if (backupIn == null) {
154: throw new IllegalStateException(
155: "Start backup process first.");
156: }
157: try {
158: return new ObjectID(backupIn.readLong());
159: } catch (Exception e) {
160: backupIn.close();
161: backupIn = null;
162: new File(env.dir + TMP_FILE_NAME).delete();
163:
164: if (e instanceof EOFException) {
165: return null;
166: } else {
167: throw e;
168: }
169: }
170: }
171:
172: public byte[] nextBackupChunk() throws Exception {
173: Transaction ta = env.transactionManager.currentTA();
174:
175: if (backupProducer == null) {
176: return null;
177: }
178:
179: ChunkOutputStream cos = backupProducer.chunkStream();
180: ObjectID id = null;
181:
182: // this order of the expressions is important
183: while (cos.getState() != ChunkOutputStream.STATE_OVERFLOW
184: && (id = nextBackupID()) != null) {
185: // System.out.println( "chunk size: " + cos.size() );
186: // System.out.println( "oid: " + id + " count=" + (++idcount));
187:
188: ObjectContainer container = ta.acquireObjectAndPin(id,
189: Lock.LEVEL_READ);
190:
191: try {
192: OzoneCompatible target = container.target();
193: // System.out.println( "target: " + target + "[" + target.getClass().getName() + "]" );
194:
195: if (target instanceof org.ozoneDB.core.admin.AdminImpl) {
196: continue;
197: }
198:
199: Object2XML o2x = new Object2XML(backupProducer, true);
200: o2x.toXML(target);
201: } finally {
202: container.unpin();
203: }
204: }
205:
206: if (id == null) {
207: backupProducer.endElement("", BACKUP_ELEMENT_NAME,
208: BACKUP_ELEMENT_NAME);
209: backupProducer.endDocument();
210: cos.setEndFlag();
211: // backupIt = null;
212: backupProducer = null;
213: }
214: byte[] temp = cos.toByteArray();
215: cos.reset();
216: env.logWriter.newEntry(this , "nextBackupChunk(): size="
217: + temp.length, LogWriter.INFO);
218: return temp;
219: }
220:
221: }
|