EMMA Coverage Report (generated Sun Feb 05 10:43:15 CET 2012)
[all classes][de.uka.ipd.sdq.sensorframework.storage.lists]

COVERAGE SUMMARY FOR SOURCE FILE [BackgroundMemoryList.java]

nameclass, %method, %block, %line, %
BackgroundMemoryList.java100% (1/1)100% (9/9)69%  (142/205)76%  (37,4/49)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class BackgroundMemoryList100% (1/1)100% (9/9)69%  (142/205)76%  (37,4/49)
initListSize (): void 100% (1/1)35%  (15/43)40%  (2,4/6)
add (int, Object): void 100% (1/1)55%  (22/40)56%  (5/9)
get (int): Object 100% (1/1)55%  (21/38)50%  (4/8)
BackgroundMemoryList (File, ISerialiser): void 100% (1/1)100% (27/27)100% (9/9)
BackgroundMemoryList (String, ISerialiser): void 100% (1/1)100% (8/8)100% (2/2)
close (): void 100% (1/1)100% (12/12)100% (5/5)
ensureCorrectChunkLoaded (int): void 100% (1/1)100% (24/24)100% (5/5)
flush (): void 100% (1/1)100% (10/10)100% (4/4)
size (): int 100% (1/1)100% (3/3)100% (1/1)

1package de.uka.ipd.sdq.sensorframework.storage.lists;
2 
3import java.io.File;
4import java.io.IOException;
5import java.io.RandomAccessFile;
6import java.util.AbstractList;
7import java.util.List;
8import java.util.RandomAccess;
9 
10/**
11 * @author Steffen Becker
12 * A generic list implementation that consumes a constant amount of main memory regardless of the number of elements in the 
13 * list. It relies on HDD memory as background storage. It uses chunks which are filled and upon fully filled swapped to disk.
14 * The list has some restrictions for this to work. First, all elements have to be serialisable with constant memory footprint. Second,
15 * deletion of elements in the list is not implemented.
16 * @param <T> The generic type parameter of the list's elements
17 */
18public class BackgroundMemoryList<T> 
19        extends AbstractList<T>
20        implements List<T>, RandomAccess {
21 
22        /**
23         * Number of list elements per list chunk
24         */
25        static final public int MEMORY_CHUNKS_SIZE = 10000;
26        
27        /**
28         * The current chunk loaded into memory
29         */
30        private Chunk<T> currentChunk = null;
31        
32        /**
33         * The background file storage in which all chunks get persisted when they are swapped from main memory
34         */
35        private RandomAccessFile raf = null;
36        
37        /**
38         * Inner state of the underlying background storage
39         */
40        boolean isClosed = true;
41        
42        /**
43         * The serialiser used to serialise the elements of the list on the background storage
44         */
45        private ISerialiser<T> serialiser;
46        
47        /**
48         * Current number of elements in the list
49         */
50        private int listSize;
51        
52        /**
53         * Constructor of a background memory list
54         * @param filename The file used as background storage
55         * @param serialiser The serialiser used to serialise the elements of the list
56         * @throws IOException Thrown if file IO fails
57         */
58        public BackgroundMemoryList(String filename, ISerialiser<T> serialiser) throws IOException {
59                this(new File(filename),serialiser);
60        }
61 
62        /**
63         * Constructor of a background memory list
64         * @param f The file used as background storage
65         * @param serialiser The serialiser used to serialise the elements of the list
66         * @throws IOException Thrown if file IO fails
67         */
68        public BackgroundMemoryList(File f, ISerialiser<T> serialiser) throws IOException {
69                raf = new RandomAccessFile(f,"rw");
70                isClosed = false;
71                this.serialiser = serialiser;
72                initListSize();
73        }
74 
75        @Override
76        public synchronized void add(int index, T e) {
77                try{
78                        ensureCorrectChunkLoaded(index);
79                        if (currentChunk == null || currentChunk.isFull()) {
80                                flush();
81                                currentChunk = new Chunk<T>(raf,serialiser);
82                        }
83                        currentChunk.add(e);
84                        this.listSize++;
85                } catch(IOException ex) {
86                        throw new RuntimeException("Background List failed",ex);
87                }
88        }
89 
90        public synchronized T get(int index) {
91                if (this.isClosed)
92                        throw new IllegalStateException("Tryed to get data from a closed background list");
93                if (index >= size())
94                        throw new ArrayIndexOutOfBoundsException("Read behind background list length");
95                try{
96                        ensureCorrectChunkLoaded(index);
97                        return currentChunk.get((int)(index-currentChunk.fromElement()));
98                } catch(IOException ex) {
99                        throw new RuntimeException("Background List failed",ex);
100                }
101        }
102 
103        /**
104         * Tests whether a chunk swapping is needed to access the list element add the given index and if so swaps the chunks
105         */
106        private void ensureCorrectChunkLoaded(int index) throws IOException {
107                if (currentChunk != null && currentChunk.accepts(index))
108                        return;
109                else {
110                        flush();
111                        currentChunk = new Chunk<T>(raf,serialiser,index / MEMORY_CHUNKS_SIZE);
112                }
113        }
114 
115        public synchronized int size() {
116                return this.listSize;
117        }
118 
119        /**
120         * Derive the list size from the size of the underlying file. Called on opening a list
121         */
122        private void initListSize() {
123                try {
124                        if (currentChunk != null && !currentChunk.isFull()) {
125                                // The current chunk is the last chunk which might contain unsaved data,
126                                // so the size is the size of all saved data + all unsaved data
127                                this.listSize = (int)(raf.length() / (serialiser.getElementLength() * MEMORY_CHUNKS_SIZE) + currentChunk.size());
128                        }
129                        this.listSize = (int)(raf.length() / serialiser.getElementLength());
130                } catch (IOException e) {
131                        throw new RuntimeException("Background list failed unexpectedly",e);
132                }
133        }
134 
135        /** Closes the background storage. The list is inaccessible afterwards
136         * @throws IOException
137         */
138        public synchronized void close() throws IOException {
139                if (!isClosed){
140                        flush();
141                        raf.close();
142                        isClosed = true;
143                }
144        }
145 
146        /** Writes all buffered data to the background storage and clears the current chunk.
147         * @throws IOException
148         */
149        public synchronized void flush() throws IOException {
150                if (currentChunk != null) {
151                        currentChunk.persist();
152                }
153                currentChunk = null;
154        }
155}

[all classes][de.uka.ipd.sdq.sensorframework.storage.lists]
EMMA 2.0.9414 (unsupported private build) (C) Vladimir Roubtsov