View Javadoc
1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one
3    * or more contributor license agreements.  See the NOTICE file
4    * distributed with this work for additional information
5    * regarding copyright ownership. The ASF licenses this file
6    * to you under the Apache License, Version 2.0 (the
7    * "License"); you may not use this file except in compliance
8    * with the License. You may obtain a copy of the License at
9    * 
10   *      http://www.apache.org/licenses/LICENSE-2.0
11   * 
12   * Unless required by applicable law or agreed to in writing, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.river.outrigger.snaplogstore;
19  
20  import org.apache.river.outrigger.OutriggerServerImpl;
21  
22  import java.io.File;
23  import java.io.FileDescriptor;
24  import java.io.IOException;
25  import java.io.ObjectOutputStream;
26  import java.io.RandomAccessFile;
27  import java.util.ArrayList;
28  import java.util.logging.Level;
29  import java.util.logging.Logger;
30  
31  import net.jini.space.InternalSpaceException;
32  
33  /**
34   *
35   * @author Sun Microsystems, Inc.
36   */
37  class SnapshotFile extends LogFile {
38      private volatile RandomAccessFile	snapshotFile = null;// current snapshot file
39      private volatile String		fileName = null; // current snapshot file name
40      private volatile String		previousFilename = null; // previous snapshot
41      private volatile ObjectOutputStream	out;	   // current snapshot stream
42      private volatile int			suffix;	   // the current suffix number
43  
44      /** Logger for logging persistent store related information */
45      private static final Logger logger = 
46  	Logger.getLogger(OutriggerServerImpl.storeLoggerName);
47  
48      /**
49       */
50      SnapshotFile(String basePath, File[] recover) throws IOException {
51  	super(basePath);
52  	ArrayList snapshots = new ArrayList();
53  	suffix = existingLogs(snapshots);
54  
55  	// Make sure there are at most two snapshots
56  	//
57  	if (snapshots.size() > 2)
58  	    throw new InternalSpaceException("More than two snapshot files "+
59  					"are present");
60  
61  	// If there are two snapshots, delete the second (newest) one
62  	//
63  	if (snapshots.size() == 2) {
64  	    File file = (File)snapshots.get(1);
65  	    file.delete();
66  
67  	    // if there are two files and suffix==1 then we restarted while
68  	    // writing the first (real) snapshot file. So report back null
69  	    // (snapshot.0 is a dummy file) and restart the file numbers.
70  	    //
71  	    if (suffix == 1) {
72  		suffix = 0;
73  		recover[0] = null;
74  	    } else {
75  		recover[0] = (File)(snapshots.get(0));
76  		previousFilename = recover[0].getName();
77  	    }
78  	} else if (snapshots.size() == 1) {
79  	    File file = (File)(snapshots.get(0));
80  	    previousFilename = file.getName();
81  
82  	    // If there is one file, and the suffix==0 then we restarted
83  	    // sometime after the "file.delete()" line above and all that
84  	    // is left is the dummy .0 snapshot file.
85  	    //
86  	    if (suffix == 0)
87  		recover[0] = null;
88  	    else
89  	    	recover[0] = file;
90  
91  	} else { // (snapshot.size() == 0) also (suffix == -1)
92  
93  	    // first time, so create a dummy .0 file
94  	    next();
95  	    commit();
96  	    recover[0] = null;
97  	}
98      }
99  
100     /**
101      * Switch this over to the next path in the list
102      */
103     ObjectOutputStream next() throws IOException {
104 
105 	suffix++;			// go to next suffix
106 	fileName = baseFile + suffix;
107 	snapshotFile = new RandomAccessFile(baseDir.getPath() + File.separator +
108 				       fileName, "rw");
109 	out = new ObjectOutputStream(new LogOutputStream(snapshotFile));
110 	return out;
111     }
112 
113     void commit() throws IOException {
114 	if (snapshotFile != null) {
115 	    try {
116 		close();   	        // close the stream and the file
117 	    } catch (IOException ignore) { } // assume this is okay
118 	}
119 
120 	// delete previous snapshot file if there was one
121 	if (previousFilename != null) {
122 	    File file = new File(baseDir, previousFilename);
123 	    file.delete();
124 	}
125 	previousFilename = fileName;
126     }
127 
128     /**
129      * Close the log, but don't remove it.
130      */
131     synchronized void close() throws IOException {
132 	if (snapshotFile != null) {
133 	    try {
134 		out.close();
135 		snapshotFile.close();
136 	    } finally {
137 		snapshotFile = null;
138 	    }
139 	}
140     }
141 
142     /**
143      * Override destroy so we can try to close snapshotFile before calling
144      * super tries to delete all the files.
145      */
146     void destroy() {
147 	try {
148 	    close();
149 	} catch (Throwable t) {
150 	    // Don't let failure keep us from deleting the files we can	    
151 	}
152 	super.destroy();
153     }
154 }