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

COVERAGE SUMMARY FOR SOURCE FILE [PageOutputStream.java]

nameclass, %method, %block, %line, %
PageOutputStream.java100% (1/1)85%  (11/13)79%  (334/423)85%  (79.5/94)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class PageOutputStream100% (1/1)85%  (11/13)79%  (334/423)85%  (79.5/94)
free (PageStreamTrunk): void 0%   (0/1)0%   (0/9)0%   (0/2)
getMinPageId (): int 0%   (0/1)0%   (0/3)0%   (0/1)
freeReserved (): void 100% (1/1)12%  (5/43)25%  (2/8)
storePage (): void 100% (1/1)40%  (8/20)75%  (3/4)
fillPage (): void 100% (1/1)66%  (25/38)86%  (6/7)
write (byte [], int, int): void 100% (1/1)83%  (50/60)87%  (16.5/19)
initNextData (): void 100% (1/1)97%  (123/127)95%  (20/21)
PageOutputStream (PageStore, int, BitField, int, boolean): void 100% (1/1)100% (36/36)100% (10/10)
close (): void 100% (1/1)100% (4/4)100% (2/2)
flush (): void 100% (1/1)100% (9/9)100% (4/4)
getCurrentDataPageId (): int 100% (1/1)100% (4/4)100% (1/1)
getSize (): long 100% (1/1)100% (8/8)100% (1/1)
reserve (int): void 100% (1/1)100% (62/62)100% (14/14)

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.store;
7 
8import org.h2.message.DbException;
9import org.h2.message.Trace;
10import org.h2.util.BitField;
11import org.h2.util.IntArray;
12 
13/**
14 * An output stream that writes into a page store.
15 */
16public class PageOutputStream {
17 
18    private PageStore store;
19    private final Trace trace;
20    private final BitField exclude;
21    private final boolean atEnd;
22    private final int minPageId;
23 
24    private int trunkPageId;
25    private int trunkNext;
26    private IntArray reservedPages = new IntArray();
27    private PageStreamTrunk trunk;
28    private int trunkIndex;
29    private PageStreamData data;
30    private int reserved;
31    private boolean needFlush;
32    private boolean writing;
33    private int pageCount;
34    private int logKey;
35 
36    /**
37     * Create a new page output stream.
38     *
39     * @param store the page store
40     * @param trunkPage the first trunk page (already allocated)
41     * @param exclude the pages not to use
42     * @param logKey the log key of the first trunk page
43     * @param atEnd whether only pages at the end of the file should be used
44     */
45    public PageOutputStream(PageStore store, int trunkPage, BitField exclude,
46            int logKey, boolean atEnd) {
47        this.trace = store.getTrace();
48        this.store = store;
49        this.trunkPageId = trunkPage;
50        this.exclude = exclude;
51        // minus one, because we increment before creating a trunk page
52        this.logKey = logKey - 1;
53        this.atEnd = atEnd;
54        minPageId = atEnd ? trunkPage : 0;
55    }
56 
57    /**
58     * Allocate the required pages so that no pages need to be allocated while
59     * writing.
60     *
61     * @param minBuffer the number of bytes to allocate
62     */
63    void reserve(int minBuffer) {
64        if (reserved < minBuffer) {
65            int pageSize = store.getPageSize();
66            int capacityPerPage = PageStreamData.getCapacity(pageSize);
67            int pages = PageStreamTrunk.getPagesAddressed(pageSize);
68            int pagesToAllocate = 0, totalCapacity = 0;
69            do {
70                // allocate x data pages plus one trunk page
71                pagesToAllocate += pages + 1;
72                totalCapacity += pages * capacityPerPage;
73            } while (totalCapacity < minBuffer);
74            int firstPageToUse = atEnd ? trunkPageId : 0;
75            store.allocatePages(reservedPages, pagesToAllocate, exclude, firstPageToUse);
76            reserved += totalCapacity;
77            if (data == null) {
78                initNextData();
79            }
80        }
81    }
82 
83    private void initNextData() {
84        int nextData = trunk == null ? -1 : trunk.getPageData(trunkIndex++);
85        if (nextData == -1) {
86            int parent = trunkPageId;
87            if (trunkNext != 0) {
88                trunkPageId = trunkNext;
89            }
90            int len = PageStreamTrunk.getPagesAddressed(store.getPageSize());
91            int[] pageIds = new int[len];
92            for (int i = 0; i < len; i++) {
93                pageIds[i] = reservedPages.get(i);
94            }
95            trunkNext = reservedPages.get(len);
96            logKey++;
97            trunk = PageStreamTrunk.create(store, parent, trunkPageId,
98                    trunkNext, logKey, pageIds);
99            trunkIndex = 0;
100            pageCount++;
101            trunk.write();
102            reservedPages.removeRange(0, len + 1);
103            nextData = trunk.getPageData(trunkIndex++);
104        }
105        data = PageStreamData.create(store, nextData, trunk.getPos(), logKey);
106        pageCount++;
107        data.initWrite();
108    }
109 
110    /**
111     * Write the data.
112     *
113     * @param b the buffer
114     * @param off the offset
115     * @param len the length
116     */
117    public void write(byte[] b, int off, int len) {
118        if (len <= 0) {
119            return;
120        }
121        if (writing) {
122            DbException.throwInternalError("writing while still writing");
123        }
124        try {
125            reserve(len);
126            writing = true;
127            while (len > 0) {
128                int l = data.write(b, off, len);
129                if (l < len) {
130                    storePage();
131                    initNextData();
132                }
133                reserved -= l;
134                off += l;
135                len -= l;
136            }
137            needFlush = true;
138        } finally {
139            writing = false;
140        }
141    }
142 
143    private void storePage() {
144        if (trace.isDebugEnabled()) {
145            trace.debug("pageOut.storePage " + data);
146        }
147        data.write();
148    }
149 
150    /**
151     * Write all data.
152     */
153    public void flush() {
154        if (needFlush) {
155            storePage();
156            needFlush = false;
157        }
158    }
159 
160    /**
161     * Close the stream.
162     */
163    public void close() {
164        store = null;
165    }
166 
167    int getCurrentDataPageId() {
168        return data.getPos();
169    }
170 
171    /**
172     * Fill the data page with zeros and write it.
173     * This is required for a checkpoint.
174     */
175    void fillPage() {
176        if (trace.isDebugEnabled()) {
177            trace.debug("pageOut.storePage fill " + data.getPos());
178        }
179        reserve(data.getRemaining() + 1);
180        reserved -= data.getRemaining();
181        data.write();
182        initNextData();
183    }
184 
185    long getSize() {
186        return pageCount * store.getPageSize();
187    }
188 
189    /**
190     * Remove a trunk page from the stream.
191     *
192     * @param t the trunk page
193     */
194    void free(PageStreamTrunk t) {
195        pageCount -= t.free(0);
196    }
197 
198    /**
199     * Free up all reserved pages.
200     */
201    void freeReserved() {
202        if (reservedPages.size() > 0) {
203            int[] array = new int[reservedPages.size()];
204            reservedPages.toArray(array);
205            reservedPages = new IntArray();
206            reserved = 0;
207            for (int p : array) {
208                store.free(p, false);
209            }
210        }
211    }
212 
213    /**
214     * Get the smallest possible page id used. This is the trunk page if only
215     * appending at the end of the file, or 0.
216     *
217     * @return the smallest possible page.
218     */
219    int getMinPageId() {
220        return minPageId;
221    }
222 
223}

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