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

COVERAGE SUMMARY FOR SOURCE FILE [Chunk.java]

nameclass, %method, %block, %line, %
Chunk.java100% (1/1)82%  (9/11)95%  (408/430)96%  (75/78)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class Chunk100% (1/1)82%  (9/11)95%  (408/430)96%  (75/78)
equals (Object): boolean 0%   (0/1)0%   (0/13)0%   (0/1)
hashCode (): int 0%   (0/1)0%   (0/3)0%   (0/1)
writeChunkHeader (WriteBuffer, int): void 100% (1/1)86%  (38/44)88%  (7/8)
Chunk (int): void 100% (1/1)100% (6/6)100% (3/3)
asString (): String 100% (1/1)100% (106/106)100% (19/19)
fromString (String): Chunk 100% (1/1)100% (90/90)100% (16/16)
getFillRate (): int 100% (1/1)100% (26/26)100% (5/5)
getFooterBytes (): byte [] 100% (1/1)100% (55/55)100% (11/11)
getMetaKey (int): String 100% (1/1)100% (10/10)100% (1/1)
readChunkHeader (ByteBuffer, long): Chunk 100% (1/1)100% (74/74)100% (12/12)
toString (): String 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.mvstore;
7 
8import java.nio.ByteBuffer;
9import java.util.HashMap;
10 
11/**
12 * A chunk of data, containing one or multiple pages.
13 * <p>
14 * Chunks are page aligned (each page is usually 4096 bytes).
15 * There are at most 67 million (2^26) chunks,
16 * each chunk is at most 2 GB large.
17 */
18public class Chunk {
19 
20    /**
21     * The maximum chunk id.
22     */
23    public static final int MAX_ID = (1 << 26) - 1;
24 
25    /**
26     * The maximum length of a chunk header, in bytes.
27     */
28    static final int MAX_HEADER_LENGTH = 1024;
29 
30    /**
31     * The length of the chunk footer. The longest footer is:
32     * chunk:ffffffff,block:ffffffffffffffff,
33     * version:ffffffffffffffff,fletcher:ffffffff
34     */
35    static final int FOOTER_LENGTH = 128;
36 
37    /**
38     * The chunk id.
39     */
40    public final int id;
41 
42    /**
43     * The start block number within the file.
44     */
45    public long block;
46 
47    /**
48     * The length in number of blocks.
49     */
50    public int len;
51 
52    /**
53     * The total number of pages in this chunk.
54     */
55    public int pageCount;
56 
57    /**
58     * The number of pages still alive.
59     */
60    public int pageCountLive;
61 
62    /**
63     * The sum of the max length of all pages.
64     */
65    public long maxLen;
66 
67    /**
68     * The sum of the max length of all pages that are in use.
69     */
70    public long maxLenLive;
71 
72    /**
73     * The garbage collection priority. Priority 0 means it needs to be
74     * collected, a high value means low priority.
75     */
76    public int collectPriority;
77 
78    /**
79     * The position of the meta root.
80     */
81    public long metaRootPos;
82 
83    /**
84     * The version stored in this chunk.
85     */
86    public long version;
87 
88    /**
89     * When this chunk was created, in milliseconds after the store was created.
90     */
91    public long time;
92 
93    /**
94     * When this chunk was no longer needed, in milliseconds after the store was
95     * created. After this, the chunk is kept alive a bit longer (in case it is
96     * referenced in older versions).
97     */
98    public long unused;
99 
100    /**
101     * The last used map id.
102     */
103    public int mapId;
104 
105    /**
106     * The predicted position of the next chunk.
107     */
108    public long next;
109 
110    Chunk(int id) {
111        this.id = id;
112    }
113 
114    /**
115     * Read the header from the byte buffer.
116     *
117     * @param buff the source buffer
118     * @param start the start of the chunk in the file
119     * @return the chunk
120     */
121    static Chunk readChunkHeader(ByteBuffer buff, long start) {
122        int pos = buff.position();
123        byte[] data = new byte[Math.min(buff.remaining(), MAX_HEADER_LENGTH)];
124        buff.get(data);
125        try {
126            for (int i = 0; i < data.length; i++) {
127                if (data[i] == '\n') {
128                    // set the position to the start of the first page
129                    buff.position(pos + i + 1);
130                    String s = new String(data, 0, i, DataUtils.LATIN).trim();
131                    return fromString(s);
132                }
133            }
134        } catch (Exception e) {
135            // there could be various reasons
136            throw DataUtils.newIllegalStateException(
137                    DataUtils.ERROR_FILE_CORRUPT,
138                    "File corrupt reading chunk at position {0}", start, e);
139        }
140        throw DataUtils.newIllegalStateException(
141                DataUtils.ERROR_FILE_CORRUPT,
142                "File corrupt reading chunk at position {0}", start);
143    }
144 
145    /**
146     * Write the chunk header.
147     *
148     * @param buff the target buffer
149     * @param minLength the minimum length
150     */
151    void writeChunkHeader(WriteBuffer buff, int minLength) {
152        long pos = buff.position();
153        buff.put(asString().getBytes(DataUtils.LATIN));
154        while (buff.position() - pos < minLength - 1) {
155            buff.put((byte) ' ');
156        }
157        if (minLength != 0 && buff.position() > minLength) {
158            throw DataUtils.newIllegalStateException(
159                    DataUtils.ERROR_INTERNAL,
160                    "Chunk metadata too long");
161        }
162        buff.put((byte) '\n');
163    }
164 
165    /**
166     * Get the metadata key for the given chunk id.
167     *
168     * @param chunkId the chunk id
169     * @return the metadata key
170     */
171    static String getMetaKey(int chunkId) {
172        return "chunk." + Integer.toHexString(chunkId);
173    }
174 
175    /**
176     * Build a block from the given string.
177     *
178     * @param s the string
179     * @return the block
180     */
181    public static Chunk fromString(String s) {
182        HashMap<String, String> map = DataUtils.parseMap(s);
183        int id = DataUtils.readHexInt(map, "chunk", 0);
184        Chunk c = new Chunk(id);
185        c.block = DataUtils.readHexLong(map, "block", 0);
186        c.len = DataUtils.readHexInt(map, "len", 0);
187        c.pageCount = DataUtils.readHexInt(map, "pages", 0);
188        c.pageCountLive = DataUtils.readHexInt(map, "livePages", c.pageCount);
189        c.mapId = DataUtils.readHexInt(map, "map", 0);
190        c.maxLen = DataUtils.readHexLong(map, "max", 0);
191        c.maxLenLive = DataUtils.readHexLong(map, "liveMax", c.maxLen);
192        c.metaRootPos = DataUtils.readHexLong(map, "root", 0);
193        c.time = DataUtils.readHexLong(map, "time", 0);
194        c.unused = DataUtils.readHexLong(map, "unused", 0);
195        c.version = DataUtils.readHexLong(map, "version", id);
196        c.next = DataUtils.readHexLong(map, "next", 0);
197        return c;
198    }
199 
200    /**
201     * Calculate the fill rate in %. 0 means empty, 100 means full.
202     *
203     * @return the fill rate
204     */
205    public int getFillRate() {
206        if (maxLenLive <= 0) {
207            return 0;
208        } else if (maxLenLive == maxLen) {
209            return 100;
210        }
211        return 1 + (int) (98 * maxLenLive / maxLen);
212    }
213 
214    @Override
215    public int hashCode() {
216        return id;
217    }
218 
219    @Override
220    public boolean equals(Object o) {
221        return o instanceof Chunk && ((Chunk) o).id == id;
222    }
223 
224    /**
225     * Get the chunk data as a string.
226     *
227     * @return the string
228     */
229    public String asString() {
230        StringBuilder buff = new StringBuilder();
231        DataUtils.appendMap(buff, "chunk", id);
232        DataUtils.appendMap(buff, "block", block);
233        DataUtils.appendMap(buff, "len", len);
234        if (maxLen != maxLenLive) {
235            DataUtils.appendMap(buff, "liveMax", maxLenLive);
236        }
237        if (pageCount != pageCountLive) {
238            DataUtils.appendMap(buff, "livePages", pageCountLive);
239        }
240        DataUtils.appendMap(buff, "map", mapId);
241        DataUtils.appendMap(buff, "max", maxLen);
242        if (next != 0) {
243            DataUtils.appendMap(buff, "next", next);
244        }
245        DataUtils.appendMap(buff, "pages", pageCount);
246        DataUtils.appendMap(buff, "root", metaRootPos);
247        DataUtils.appendMap(buff, "time", time);
248        if (unused != 0) {
249            DataUtils.appendMap(buff, "unused", unused);
250        }
251        DataUtils.appendMap(buff, "version", version);
252        return buff.toString();
253    }
254 
255    byte[] getFooterBytes() {
256        StringBuilder buff = new StringBuilder();
257        DataUtils.appendMap(buff, "chunk", id);
258        DataUtils.appendMap(buff, "block", block);
259        DataUtils.appendMap(buff, "version", version);
260        byte[] bytes = buff.toString().getBytes(DataUtils.LATIN);
261        int checksum = DataUtils.getFletcher32(bytes, bytes.length);
262        DataUtils.appendMap(buff, "fletcher", checksum);
263        while (buff.length() < Chunk.FOOTER_LENGTH - 1) {
264            buff.append(' ');
265        }
266        buff.append("\n");
267        return buff.toString().getBytes(DataUtils.LATIN);
268    }
269 
270    @Override
271    public String toString() {
272        return asString();
273    }
274 
275}
276 

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