/** * Write a long value to disk atomically. Either succeeds or an exception * is thrown. * @param name file name to write the long to * @param value the long value to write to the named file * @throws IOException if the file cannot be written atomically */ private void writeLongToFile(String name, long value) throws IOException { File file = new File(logFactory.getSnapDir(), name); AtomicFileOutputStream out = new AtomicFileOutputStream(file); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out)); boolean aborted = false; try { bw.write(Long.toString(value)); bw.flush(); out.flush(); } catch (IOException e) { LOG.error("Failed to write new file " + file, e); // worst case here the tmp file/resources(fd) are not cleaned up // and the caller will be notified (IOException) aborted = true; out.abort(); throw e; } finally { if (!aborted) { // if the close operation (rename) fails we'll get notified. // worst case the tmp file may still exist out.close(); } } }
/** * Test case where there is no existing file */ @Test public void testOverwriteFile() throws IOException { assertTrue("Creating empty dst file", dstFile.createNewFile()); OutputStream fos = new AtomicFileOutputStream(dstFile); assertTrue("Empty file still exists", dstFile.exists()); fos.write(TEST_STRING.getBytes()); fos.flush(); // Original contents still in place assertEquals("", ClientBase.readFile(dstFile)); fos.close(); // New contents replace original file String readBackData = ClientBase.readFile(dstFile); assertEquals(TEST_STRING, readBackData); }
/** * Ensure the tmp file is cleaned up and dstFile is untouched when * aborting an existing file overwrite. */ @Test public void testAbortExistingFileAfterFlush() throws IOException { FileOutputStream fos1 = new FileOutputStream(dstFile); fos1.write(TEST_STRING.getBytes()); fos1.close(); AtomicFileOutputStream fos2 = new AtomicFileOutputStream(dstFile); fos2.write(TEST_STRING_2.getBytes()); fos2.flush(); fos2.abort(); // Should not have touched original file assertEquals(TEST_STRING, ClientBase.readFile(dstFile)); assertEquals(1, testDir.list().length); }
/** * serialize the datatree and session into the file snapshot * @param dt the datatree to be serialized * @param sessions the sessions to be serialized * @param snapShot the file to store snapshot into * @param fsync sync the file immediately after write */ public synchronized void serialize(DataTree dt, Map<Long, Integer> sessions, File snapShot, boolean fsync) throws IOException { if (!close) { try (CheckedOutputStream crcOut = new CheckedOutputStream(new BufferedOutputStream(fsync ? new AtomicFileOutputStream(snapShot) : new FileOutputStream(snapShot)), new Adler32())) { //CheckedOutputStream cout = new CheckedOutputStream() OutputArchive oa = BinaryOutputArchive.getArchive(crcOut); FileHeader header = new FileHeader(SNAP_MAGIC, VERSION, dbId); serialize(dt, sessions, oa, header); long val = crcOut.getChecksum().getValue(); oa.writeLong(val, "val"); oa.writeString("/", "path"); crcOut.flush(); } } }
static void writeLongToFile(File file, long value) throws IOException { AtomicFileOutputStream out = new AtomicFileOutputStream(file); BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(out)); try { bw.write(Long.toString(value)); bw.flush(); out.flush(); out.close(); } catch (IOException e) { LOG.error("Failed to write new file " + file, e); out.abort(); throw e; } }
/** * Test case where there is no existing file */ @Test public void testWriteNewFile() throws IOException { OutputStream fos = new AtomicFileOutputStream(dstFile); assertFalse(dstFile.exists()); fos.write(TEST_STRING.getBytes()); fos.flush(); assertFalse(dstFile.exists()); fos.close(); assertTrue(dstFile.exists()); String readBackData = ClientBase.readFile(dstFile); assertEquals(TEST_STRING, readBackData); }
/** * Create a stream that fails to flush at close time */ private OutputStream createFailingStream() throws FileNotFoundException { return new AtomicFileOutputStream(dstFile) { @Override public void flush() throws IOException { throw new IOException("injected failure"); } }; }