EMMA Coverage Report (generated Sun Mar 01 22:06:14 CET 2015)
[all classes][org.h2.engine]

COVERAGE SUMMARY FOR SOURCE FILE [UndoLogRecord.java]

nameclass, %method, %block, %line, %
UndoLogRecord.java100% (1/1)36%  (5/14)20%  (83/410)23%  (22.8/101)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class UndoLogRecord100% (1/1)36%  (5/14)20%  (83/410)23%  (22.8/101)
append (Data, UndoLog): void 0%   (0/1)0%   (0/74)0%   (0/16)
canStore (): boolean 0%   (0/1)0%   (0/8)0%   (0/3)
getFilePos (): long 0%   (0/1)0%   (0/4)0%   (0/1)
getTable (): Table 0%   (0/1)0%   (0/3)0%   (0/1)
invalidatePos (): void 0%   (0/1)0%   (0/7)0%   (0/3)
load (Data, FileStore, UndoLog): void 0%   (0/1)0%   (0/64)0%   (0/14)
load (Data, UndoLog): void 0%   (0/1)0%   (0/66)0%   (0/15)
loadFromBuffer (Data, UndoLog): UndoLogRecord 0%   (0/1)0%   (0/26)0%   (0/6)
save (Data, FileStore, UndoLog): void 0%   (0/1)0%   (0/27)0%   (0/7)
undo (Session): void 100% (1/1)53%  (51/97)52%  (13/25)
isStored (): boolean 100% (1/1)75%  (6/8)75%  (0.8/1)
UndoLogRecord (Table, short, Row): void 100% (1/1)100% (15/15)100% (6/6)
commit (): void 100% (1/1)100% (8/8)100% (2/2)
getRow (): Row 100% (1/1)100% (3/3)100% (1/1)

1/*
2 * Copyright 2004-2014 H2 Group. Multiple-Licensed under the MPL 2.0,
3 * and the EPL 1.0 (http://h2database.com/html/license.html).
4 * Initial Developer: H2 Group
5 */
6package org.h2.engine;
7 
8import org.h2.api.ErrorCode;
9import org.h2.message.DbException;
10import org.h2.result.Row;
11import org.h2.store.Data;
12import org.h2.store.FileStore;
13import org.h2.table.Table;
14import org.h2.value.Value;
15 
16/**
17 * An entry in a undo log.
18 */
19public class UndoLogRecord {
20 
21    /**
22     * Operation type meaning the row was inserted.
23     */
24    public static final short INSERT = 0;
25 
26    /**
27     * Operation type meaning the row was deleted.
28     */
29    public static final short DELETE = 1;
30 
31    private static final int IN_MEMORY = 0, STORED = 1, IN_MEMORY_INVALID = 2;
32    private Table table;
33    private Row row;
34    private short operation;
35    private short state;
36    private int filePos;
37 
38    /**
39     * Create a new undo log record
40     *
41     * @param table the table
42     * @param op the operation type
43     * @param row the row that was deleted or inserted
44     */
45    UndoLogRecord(Table table, short op, Row row) {
46        this.table = table;
47        this.row = row;
48        this.operation = op;
49        this.state = IN_MEMORY;
50    }
51 
52    /**
53     * Check if the log record is stored in the file.
54     *
55     * @return true if it is
56     */
57    boolean isStored() {
58        return state == STORED;
59    }
60 
61    /**
62     * Check if this undo log record can be store. Only record can be stored if
63     * the table has a unique index.
64     *
65     * @return if it can be stored
66     */
67    boolean canStore() {
68        // if large transactions are enabled, this method is not called
69        if (table.getUniqueIndex() != null) {
70            return true;
71        }
72        return false;
73    }
74 
75    /**
76     * Un-do the operation. If the row was inserted before, it is deleted now,
77     * and vice versa.
78     *
79     * @param session the session
80     */
81    void undo(Session session) {
82        Database db = session.getDatabase();
83        switch (operation) {
84        case INSERT:
85            if (state == IN_MEMORY_INVALID) {
86                state = IN_MEMORY;
87            }
88            if (db.getLockMode() == Constants.LOCK_MODE_OFF) {
89                if (row.isDeleted()) {
90                    // it might have been deleted by another thread
91                    return;
92                }
93            }
94            try {
95                row.setDeleted(false);
96                table.removeRow(session, row);
97                table.fireAfterRow(session, row, null, true);
98            } catch (DbException e) {
99                if (session.getDatabase().getLockMode() == Constants.LOCK_MODE_OFF
100                        && e.getErrorCode() == ErrorCode.ROW_NOT_FOUND_WHEN_DELETING_1) {
101                    // it might have been deleted by another thread
102                    // ignore
103                } else {
104                    throw e;
105                }
106            }
107            break;
108        case DELETE:
109            try {
110                table.addRow(session, row);
111                table.fireAfterRow(session, null, row, true);
112                // reset session id, otherwise other sessions think
113                // that this row was inserted by this session
114                row.commit();
115            } catch (DbException e) {
116                if (session.getDatabase().getLockMode() == Constants.LOCK_MODE_OFF
117                        && e.getSQLException().getErrorCode() == ErrorCode.DUPLICATE_KEY_1) {
118                    // it might have been added by another thread
119                    // ignore
120                } else {
121                    throw e;
122                }
123            }
124            break;
125        default:
126            DbException.throwInternalError("op=" + operation);
127        }
128    }
129 
130    /**
131     * Append the row to the buffer.
132     *
133     * @param buff the buffer
134     * @param log the undo log
135     */
136    void append(Data buff, UndoLog log) {
137        int p = buff.length();
138        buff.writeInt(0);
139        buff.writeInt(operation);
140        buff.writeByte(row.isDeleted() ? (byte) 1 : (byte) 0);
141        buff.writeInt(log.getTableId(table));
142        buff.writeLong(row.getKey());
143        buff.writeInt(row.getSessionId());
144        int count = row.getColumnCount();
145        buff.writeInt(count);
146        for (int i = 0; i < count; i++) {
147            Value v = row.getValue(i);
148            buff.checkCapacity(buff.getValueLen(v));
149            buff.writeValue(v);
150        }
151        buff.fillAligned();
152        buff.setInt(p, (buff.length() - p) / Constants.FILE_BLOCK_SIZE);
153    }
154 
155    /**
156     * Save the row in the file using a buffer.
157     *
158     * @param buff the buffer
159     * @param file the file
160     * @param log the undo log
161     */
162    void save(Data buff, FileStore file, UndoLog log) {
163        buff.reset();
164        append(buff, log);
165        filePos = (int) (file.getFilePointer() / Constants.FILE_BLOCK_SIZE);
166        file.write(buff.getBytes(), 0, buff.length());
167        row = null;
168        state = STORED;
169    }
170 
171    /**
172     * Load an undo log record row using a buffer.
173     *
174     * @param buff the buffer
175     * @param log the log
176     * @return the undo log record
177     */
178    static UndoLogRecord loadFromBuffer(Data buff, UndoLog log) {
179        UndoLogRecord rec = new UndoLogRecord(null, (short) 0, null);
180        int pos = buff.length();
181        int len = buff.readInt() * Constants.FILE_BLOCK_SIZE;
182        rec.load(buff, log);
183        buff.setPos(pos + len);
184        return rec;
185    }
186 
187    /**
188     * Load an undo log record row using a buffer.
189     *
190     * @param buff the buffer
191     * @param file the source file
192     * @param log the log
193     */
194    void load(Data buff, FileStore file, UndoLog log) {
195        int min = Constants.FILE_BLOCK_SIZE;
196        log.seek(filePos);
197        buff.reset();
198        file.readFully(buff.getBytes(), 0, min);
199        int len = buff.readInt() * Constants.FILE_BLOCK_SIZE;
200        buff.checkCapacity(len);
201        if (len - min > 0) {
202            file.readFully(buff.getBytes(), min, len - min);
203        }
204        int oldOp = operation;
205        load(buff, log);
206        if (SysProperties.CHECK) {
207            if (operation != oldOp) {
208                DbException.throwInternalError("operation=" + operation + " op=" + oldOp);
209            }
210        }
211    }
212 
213    private void load(Data buff, UndoLog log) {
214        operation = (short) buff.readInt();
215        boolean deleted = buff.readByte() == 1;
216        table = log.getTable(buff.readInt());
217        long key = buff.readLong();
218        int sessionId = buff.readInt();
219        int columnCount = buff.readInt();
220        Value[] values = new Value[columnCount];
221        for (int i = 0; i < columnCount; i++) {
222            values[i] = buff.readValue();
223        }
224        row = new Row(values, Row.MEMORY_CALCULATE);
225        row.setKey(key);
226        row.setDeleted(deleted);
227        row.setSessionId(sessionId);
228        state = IN_MEMORY_INVALID;
229    }
230 
231    /**
232     * Get the table.
233     *
234     * @return the table
235     */
236    public Table getTable() {
237        return table;
238    }
239 
240    /**
241     * Get the position in the file.
242     *
243     * @return the file position
244     */
245    public long getFilePos() {
246        return filePos;
247    }
248 
249    /**
250     * This method is called after the operation was committed.
251     * It commits the change to the indexes.
252     */
253    void commit() {
254        table.commit(operation, row);
255    }
256 
257    /**
258     * Get the row that was deleted or inserted.
259     *
260     * @return the row
261     */
262    public Row getRow() {
263        return row;
264    }
265 
266    /**
267     * Change the state from IN_MEMORY to IN_MEMORY_INVALID. This method is
268     * called if a later record was read from the temporary file, and therefore
269     * the position could have changed.
270     */
271    void invalidatePos() {
272        if (this.state == IN_MEMORY) {
273            state = IN_MEMORY_INVALID;
274        }
275    }
276}

[all classes][org.h2.engine]
EMMA 2.0.5312 (C) Vladimir Roubtsov