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

COVERAGE SUMMARY FOR SOURCE FILE [UndoLog.java]

nameclass, %method, %block, %line, %
UndoLog.java100% (1/1)60%  (6/10)24%  (126/536)27%  (30.6/115)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class UndoLog100% (1/1)60%  (6/10)24%  (126/536)27%  (30.6/115)
getTable (int): Table 0%   (0/1)0%   (0/7)0%   (0/1)
getTableId (Table): int 0%   (0/1)0%   (0/18)0%   (0/5)
saveIfPossible (UndoLogRecord, Data): void 0%   (0/1)0%   (0/19)0%   (0/4)
seek (long): void 0%   (0/1)0%   (0/7)0%   (0/2)
add (UndoLogRecord): void 100% (1/1)14%  (29/209)12%  (5/40)
getLast (): UndoLogRecord 100% (1/1)16%  (28/174)18%  (6.4/36)
size (): int 100% (1/1)42%  (10/24)40%  (2/5)
clear (): void 100% (1/1)64%  (16/25)67%  (6/9)
removeLast (boolean): void 100% (1/1)71%  (24/34)75%  (5.2/7)
UndoLog (Session): void 100% (1/1)100% (19/19)100% (6/6)

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 java.util.ArrayList;
9import java.util.HashMap;
10import org.h2.message.DbException;
11import org.h2.store.Data;
12import org.h2.store.FileStore;
13import org.h2.table.Table;
14import org.h2.util.New;
15 
16/**
17 * Each session keeps a undo log if rollback is required.
18 */
19public class UndoLog {
20 
21    private final Database database;
22    private final ArrayList<Long> storedEntriesPos = New.arrayList();
23    private final ArrayList<UndoLogRecord> records = New.arrayList();
24    private FileStore file;
25    private Data rowBuff;
26    private int memoryUndo;
27    private int storedEntries;
28    private HashMap<Integer, Table> tables;
29    private final boolean largeTransactions;
30 
31    /**
32     * Create a new undo log for the given session.
33     *
34     * @param session the session
35     */
36    UndoLog(Session session) {
37        this.database = session.getDatabase();
38        largeTransactions = database.getSettings().largeTransactions;
39    }
40 
41    /**
42     * Get the number of active rows in this undo log.
43     *
44     * @return the number of rows
45     */
46    int size() {
47        if (largeTransactions) {
48            return storedEntries + records.size();
49        }
50        if (SysProperties.CHECK && memoryUndo > records.size()) {
51            DbException.throwInternalError();
52        }
53        return records.size();
54    }
55 
56    /**
57     * Clear the undo log. This method is called after the transaction is
58     * committed.
59     */
60    void clear() {
61        records.clear();
62        storedEntries = 0;
63        storedEntriesPos.clear();
64        memoryUndo = 0;
65        if (file != null) {
66            file.closeAndDeleteSilently();
67            file = null;
68            rowBuff = null;
69        }
70    }
71 
72    /**
73     * Get the last record and remove it from the list of operations.
74     *
75     * @return the last record
76     */
77    public UndoLogRecord getLast() {
78        int i = records.size() - 1;
79        if (largeTransactions) {
80            if (i < 0 && storedEntries > 0) {
81                int last = storedEntriesPos.size() - 1;
82                long pos = storedEntriesPos.get(last);
83                storedEntriesPos.remove(last);
84                long end = file.length();
85                int bufferLength = (int) (end - pos);
86                Data buff = Data.create(database, bufferLength);
87                file.seek(pos);
88                file.readFully(buff.getBytes(), 0, bufferLength);
89                while (buff.length() < bufferLength) {
90                    UndoLogRecord e = UndoLogRecord.loadFromBuffer(buff, this);
91                    records.add(e);
92                    memoryUndo++;
93                }
94                storedEntries -= records.size();
95                file.setLength(pos);
96                file.seek(pos);
97            }
98            i = records.size() - 1;
99        }
100        UndoLogRecord entry = records.get(i);
101        if (entry.isStored()) {
102            int start = Math.max(0, i - database.getMaxMemoryUndo() / 2);
103            UndoLogRecord first = null;
104            for (int j = start; j <= i; j++) {
105                UndoLogRecord e = records.get(j);
106                if (e.isStored()) {
107                    e.load(rowBuff, file, this);
108                    memoryUndo++;
109                    if (first == null) {
110                        first = e;
111                    }
112                }
113            }
114            for (int k = 0; k < i; k++) {
115                UndoLogRecord e = records.get(k);
116                e.invalidatePos();
117            }
118            seek(first.getFilePos());
119        }
120        return entry;
121    }
122 
123    /**
124     * Go to the right position in the file.
125     *
126     * @param filePos the position in the file
127     */
128    void seek(long filePos) {
129        file.seek(filePos * Constants.FILE_BLOCK_SIZE);
130    }
131 
132    /**
133     * Remove the last record from the list of operations.
134     *
135     * @param trimToSize if the undo array should shrink to conserve memory
136     */
137    void removeLast(boolean trimToSize) {
138        int i = records.size() - 1;
139        UndoLogRecord r = records.remove(i);
140        if (!r.isStored()) {
141            memoryUndo--;
142        }
143        if (trimToSize && i > 1024 && (i & 1023) == 0) {
144            records.trimToSize();
145        }
146    }
147 
148    /**
149     * Append an undo log entry to the log.
150     *
151     * @param entry the entry
152     */
153    void add(UndoLogRecord entry) {
154        records.add(entry);
155        if (largeTransactions) {
156            memoryUndo++;
157            if (memoryUndo > database.getMaxMemoryUndo() &&
158                    database.isPersistent() &&
159                    !database.isMultiVersion()) {
160                if (file == null) {
161                    String fileName = database.createTempFile();
162                    file = database.openFile(fileName, "rw", false);
163                    file.setCheckedWriting(false);
164                    file.setLength(FileStore.HEADER_LENGTH);
165                }
166                Data buff = Data.create(database, Constants.DEFAULT_PAGE_SIZE);
167                for (int i = 0; i < records.size(); i++) {
168                    UndoLogRecord r = records.get(i);
169                    buff.checkCapacity(Constants.DEFAULT_PAGE_SIZE);
170                    r.append(buff, this);
171                    if (i == records.size() - 1 || buff.length() > Constants.UNDO_BLOCK_SIZE) {
172                        storedEntriesPos.add(file.getFilePointer());
173                        file.write(buff.getBytes(), 0, buff.length());
174                        buff.reset();
175                    }
176                }
177                storedEntries += records.size();
178                memoryUndo = 0;
179                records.clear();
180                file.autoDelete();
181                return;
182            }
183        } else {
184            if (!entry.isStored()) {
185                memoryUndo++;
186            }
187            if (memoryUndo > database.getMaxMemoryUndo() &&
188                    database.isPersistent() &&
189                    !database.isMultiVersion()) {
190                if (file == null) {
191                    String fileName = database.createTempFile();
192                    file = database.openFile(fileName, "rw", false);
193                    file.setCheckedWriting(false);
194                    file.seek(FileStore.HEADER_LENGTH);
195                    rowBuff = Data.create(database, Constants.DEFAULT_PAGE_SIZE);
196                    Data buff = rowBuff;
197                    for (int i = 0; i < records.size(); i++) {
198                        UndoLogRecord r = records.get(i);
199                        saveIfPossible(r, buff);
200                    }
201                } else {
202                    saveIfPossible(entry, rowBuff);
203                }
204                file.autoDelete();
205            }
206        }
207    }
208 
209    private void saveIfPossible(UndoLogRecord r, Data buff) {
210        if (!r.isStored() && r.canStore()) {
211            r.save(buff, file, this);
212            memoryUndo--;
213        }
214    }
215 
216    /**
217     * Get the table id for this undo log. If the table is not registered yet,
218     * this is done as well.
219     *
220     * @param table the table
221     * @return the id
222     */
223    int getTableId(Table table) {
224        int id = table.getId();
225        if (tables == null) {
226            tables = New.hashMap();
227        }
228        // need to overwrite the old entry, because the old object
229        // might be deleted in the meantime
230        tables.put(id, table);
231        return id;
232    }
233 
234    /**
235     * Get the table for this id. The table must be registered for this undo log
236     * first by calling getTableId.
237     *
238     * @param id the table id
239     * @return the table object
240     */
241    Table getTable(int id) {
242        return tables.get(id);
243    }
244 
245}

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