File: FileEdgeCaseTest.java

package info (click to toggle)
libdb-je-java 3.3.98-3
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 13,052 kB
  • sloc: java: 153,077; xml: 2,034; makefile: 3
file content (142 lines) | stat: -rw-r--r-- 4,546 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/*-
 * See the file LICENSE for redistribution information.
 *
 * Copyright (c) 2002,2010 Oracle.  All rights reserved.
 *
 * $Id: FileEdgeCaseTest.java,v 1.6.2.2 2010/01/04 15:30:44 cwl Exp $
 */

package com.sleepycat.je.log;

import java.io.File;
import java.io.IOException;
import java.io.RandomAccessFile;

import junit.framework.TestCase;

import com.sleepycat.je.DatabaseException;
import com.sleepycat.je.DbInternal;
import com.sleepycat.je.Environment;
import com.sleepycat.je.EnvironmentConfig;
import com.sleepycat.je.dbi.EnvironmentImpl;
import com.sleepycat.je.recovery.NoRootException;
import com.sleepycat.je.util.TestUtils;

public class FileEdgeCaseTest extends TestCase {

    private File envHome;
    private Environment env;
    private String firstFile;

    public FileEdgeCaseTest() {
        envHome = new File(System.getProperty(TestUtils.DEST_DIR));
    }

    public void setUp()
        throws IOException {

        TestUtils.removeLogFiles("Setup", envHome, false);
    }

    public void tearDown()
        throws Exception {

        /*
	 * Close down environments in case the unit test failed so that the log
	 * files can be removed.
         */
        try {
            if (env != null) {
                env.close();
                env = null;
            }
        } catch (DatabaseException e) {
            e.printStackTrace();
            // ok, the test closed it
        }
       TestUtils.removeLogFiles("TearDown", envHome, false);
    }

    /**
     * SR #15133
     * Create a JE environment with a single log file and a checksum
     * exception in the second entry in the log file.
     *
     * When an application attempts to open this JE environment, JE truncates
     * the log file at the point before the bad checksum, because it assumes
     * that bad entries at the end of the log are the result of incompletely
     * flushed writes from the last environment use.  However, the truncated
     * log doesn't have a valid environment root, so JE complains and asks the
     * application to move aside the existing log file (via the exception
     * message). The resulting environment has a single log file, with
     * a single valid entry, which is the file header.
     *
     * Any subsequent attempts to open the environment should also fail at the
     * same point. In the error case reported by this SR, we didn't handle this
     * single log file/single file header case right, and subsequent opens
     * first truncated before the file header, leaving a 0 length log, and
     * then proceeded to write error trace messages into the log. This
     * resulted in a log file with no file header, (but with trace messages)
     * and any following opens got unpredictable errors like
     * ClassCastExceptions and BufferUnderflows.
     *
     * The correct situation is to continue to get the same exception.
     */
    public void testPostChecksumError()
        throws IOException, DatabaseException {

        EnvironmentConfig config = new EnvironmentConfig();
        config.setAllowCreate(true);
        env = new Environment(envHome, config);

        EnvironmentImpl envImpl = DbInternal.envGetEnvironmentImpl(env);
        FileManager fm = envImpl.getFileManager();
        firstFile = fm.getFullFileName(0, FileManager.JE_SUFFIX);

        env.close();
        env = null;

        /* Intentionally corrupt the second entry. */
        corruptSecondEntry();

        /*
         * Next attempt to open the environment should fail with a
         * NoRootException
         */
        try {
            env = new Environment(envHome, config);
        } catch (NoRootException expected) {
        }

        /*
         * Next attempt to open the environment should fail with a
         * NoRootException
         */
        try {
            env = new Environment(envHome, config);
        } catch (NoRootException expected) {
        }
    }

    /**
     * Write junk into the second log entry, after the file header.
     */
    private void corruptSecondEntry()
        throws IOException {

        RandomAccessFile file =
            new RandomAccessFile(firstFile,
                                 FileManager.FileMode.
                                 READWRITE_MODE.getModeValue());

        try {
            byte[] junk = new byte[20];
            file.seek(FileManager.firstLogEntryOffset());
            file.write(junk);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            file.close();
        }
    }
}