EMMA Coverage Report (generated Tue Apr 17 08:51:20 BST 2007)
[all classes][org.jtoolkit.essence.data.impl]

COVERAGE SUMMARY FOR SOURCE FILE [FileSetStore.java]

nameclass, %method, %block, %line, %
FileSetStore.java100% (1/1)100% (7/7)58%  (478/824)73%  (99.1/136)

COVERAGE BREAKDOWN BY CLASS AND METHOD

nameclass, %method, %block, %line, %
     
class FileSetStore100% (1/1)100% (7/7)58%  (478/824)73%  (99.1/136)
FileSetStore (String, Store$CollectionType, DataValueClass, DataValueClass, S... 100% (1/1)47%  (187/396)64%  (38.4/60)
clear (): void 100% (1/1)58%  (64/110)74%  (13.4/18)
notifyUpdate (Object, Object): void 100% (1/1)62%  (32/52)84%  (8.4/10)
close (): void 100% (1/1)63%  (22/35)82%  (6.6/8)
run (): void 100% (1/1)68%  (48/71)70%  (7.8/11)
flush (String): boolean 100% (1/1)78%  (121/156)84%  (23.5/28)
<static initializer> 100% (1/1)100% (4/4)100% (1/1)

1package org.jtoolkit.essence.data.impl;
2 
3import org.apache.commons.logging.Log;
4import static org.apache.commons.logging.LogFactory.getLog;
5import org.jetbrains.annotations.NotNull;
6import org.jetbrains.annotations.Nullable;
7import static org.jtoolkit.essence.app.pojo.DatableUtils.readObjects;
8import static org.jtoolkit.essence.app.pojo.DatableUtils.writeObjects;
9import org.jtoolkit.essence.app.pojo.impl.DataValueClass;
10import org.jtoolkit.essence.concurrency.Concurrency;
11import org.jtoolkit.essence.concurrency.ThreadSafe;
12import org.jtoolkit.essence.utils.FilenameMap;
13import org.jtoolkit.essence.utils.IOUtils;
14 
15import java.io.*;
16import java.util.Collection;
17import java.util.LinkedHashSet;
18import java.util.Set;
19import java.util.concurrent.Future;
20import java.util.concurrent.TimeUnit;
21 
22/*
23   Copyright 2006 Peter Lawrey
24 
25   Licensed under the Apache License, Version 2.0 (the "License");
26   you may not use this file except in compliance with the License.
27   You may obtain a copy of the License at
28 
29       http://www.apache.org/licenses/LICENSE-2.0
30 
31   Unless required by applicable law or agreed to in writing, software
32   distributed under the License is distributed on an &quot;AS IS&quot; BASIS,
33   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
34   See the License for the specific language governing permissions and
35   limitations under the License.
36*/
37 
38/**
39 * @author Peter Lawrey
40 */
41@ThreadSafe(Concurrency.CONCURRENT_READ_WRITE)
42public class FileSetStore<K, V> extends MemoryStore<K, V> implements Flushable {
43    private static final Log LOG = getLog(FileSetStore.class);
44    private static final long SEMI_SYNC_PERIOD = 25; // ms
45    private static final long ASYNC_PERIOD = 500; // ms
46    private static final String KEYS_VALUES = "Keys and Values";
47 
48    private final String dirname;
49    private final FilenameMap<K> filenameMap = new FilenameMap<K>();
50    private final boolean syncWrite;
51    private final Set<String> dirty = new LinkedHashSet<String>();
52    private final Future updateTask;
53    private final Object diskLock = new Object();
54 
55    public FileSetStore(@NotNull String name, @NotNull CollectionType collectionType,
56                        @Nullable DataValueClass<K> keyClass, @NotNull DataValueClass<V> valueClass, @NotNull String dirname,
57                        @NotNull ReadMode readMode, @NotNull PersistMode persistMode) throws IOException {
58        super(name, collectionType, keyClass, valueClass, readMode, persistMode);
59        this.dirname = dirname;
60        File dir = new File(dirname);
61        dir.mkdirs();
62 
63        File[] files = dir.listFiles();
64        if (files == null) {
65            if (LOG.isInfoEnabled()) LOG.info(name + ": Directory " + dirname + " does not exist, creating.");
66        } else if (getReadMode() == ReadMode.NONE) {
67            if (LOG.isInfoEnabled()) LOG.info(name + ": Not reading in ReadMode.NONE");
68        } else {
69            if (LOG.isDebugEnabled()) LOG.debug(name + ": Loading " + files.length + " files.");
70            for (File file : files) {
71//                if (LOCK_FILE.equals(file.getName())) continue;
72                String filename = file.getName();
73                if (filename.endsWith(".new")) {
74                    new File(filename).delete();
75                    continue;
76                }
77                DataInputStream in = null;
78                try {
79                    in = new DataInputStream(IOUtils.getInputStream(file.toString()));
80                    try {
81                        String fileFormat = in.readUTF();
82                        if (!fileFormat.equals(KEYS_VALUES))
83                            throw new UnsupportedEncodingException("Unable to read file " + file + ", format not supported " + fileFormat);
84                    } catch (IOException ignored) {
85                        throw new UnsupportedEncodingException("Unable to read file " + file + ", unknown format not supported");
86                    }
87                    Object[] keys = readObjects(in, 0, Integer.MAX_VALUE);
88                    Object[] values = readObjects(in, 0, Integer.MAX_VALUE);
89                    if (keys.length != values.length)
90                        throw new StreamCorruptedException(name + ": Keys= " + keys.length + ", Values= " + values.length);
91                    for (int i = 0; i < keys.length; i++) {
92                        K key = (K) keys[i];
93                        V value = (V) values[i];
94                        if (value != null) {
95                            V prev = doPut(key, value, true, true);
96                            if (prev != null) {
97                                if (!prev.equals(value))
98                                    LOG.warn(name + ": previous entry for key " + key + " detected. was " + prev + " now " + value);
99                                dirty.add(filenameMap.acquireFilenameForKey(key));
100                            }
101                        }
102                        filenameMap.put(filename, key);
103                    }
104                } catch (EOFException eof) {
105                    LOG.warn(name + ": File was corrupt. " + file + ' ' + eof);
106                } catch (FileNotFoundException fnfe) {
107                    LOG.warn(name + ": File disappeared while reading file " + file + ' ' + fnfe);
108                } finally {
109                    IOUtils.close(in);
110                }
111            }
112            if (LOG.isDebugEnabled() && files.length > 0) LOG.debug(name + ": ... Found " + getSize() + " entries.");
113        }
114        Flusher flusher = new Flusher(dirty, this);
115        boolean syncWrite = false;
116        if (persistMode == PersistMode.SEMI_SYNC || persistMode == PersistMode.ANY) {
117            updateTask = getStoreMonitor().scheduleAtFixedRate(flusher, SEMI_SYNC_PERIOD, SEMI_SYNC_PERIOD, TimeUnit.MILLISECONDS);
118            filenameMap.setTargetCount(500);
119        } else if (persistMode == PersistMode.ASYNC) {
120            updateTask = getStoreMonitor().scheduleAtFixedRate(flusher, ASYNC_PERIOD, ASYNC_PERIOD, TimeUnit.MILLISECONDS);
121            filenameMap.setTargetCount(2000);
122        } else {
123            updateTask = null;
124            syncWrite = true;
125            filenameMap.setTargetCount(16);
126        }
127        this.syncWrite = syncWrite;
128    }
129 
130    protected void clear() {
131        super.clear();
132        if (!canWrite()) return;
133 
134        File dir = new File(dirname);
135        File[] files;
136 
137        synchronized (diskLock) {
138            files = dir.listFiles();
139            if (files == null) return;
140            filenameMap.clear();
141            if (syncWrite) {
142                for (File f : files)
143                    if (!f.delete())
144                        LOG.warn(getName() + ": Unable to remove " + f);
145            }
146        }
147        if (!syncWrite) {
148            synchronized (dirty) {
149                for (File f : files)
150                    dirty.add(f.getName());
151            }
152        }
153    }
154 
155    public void close() {
156        boolean closed = isClosed();
157        super.close();
158        if (updateTask != null) updateTask.cancel(false);
159        if (LOG.isDebugEnabled() && !closed)
160            LOG.debug(getName() + ": Closing.");
161        if (canWrite()) {
162            run();
163        }
164    }
165 
166    protected void notifyUpdate(@NotNull K key, @Nullable V newValue) {
167        if (closed)
168            LOG.error(getName() + ": Update after closed!");
169        if (canWrite()) {
170            String filenameToFlush = filenameMap.acquireFilenameForKey(key);
171            if (!syncWrite || !flush(filenameToFlush)) {
172                synchronized (dirty) {
173                    dirty.add(filenameToFlush);
174                }
175            }
176        }
177        super.notifyUpdate(key, newValue);
178    }
179 
180    private void run() {
181        String[] dirtyFilenames;
182        synchronized (dirty) {
183            if (dirty.isEmpty()) return;
184            dirtyFilenames = dirty.toArray(new String[dirty.size()]);
185            dirty.clear();
186        }
187        for (String dirtyFilename : dirtyFilenames)
188            if (!flush(dirtyFilename)) {
189                synchronized (dirty) {
190                    dirty.add(dirtyFilename);
191                }
192            }
193    }
194 
195    public boolean flush(String filename) {
196        DataOutputStream out = null;
197        try {
198            synchronized (diskLock) {
199                File parentFile = new File(dirname);
200                File file = new File(parentFile, filename);
201 
202                IOUtils.deleteIfTmp(file);
203                File file2 = IOUtils.getNewFile(dirname + '/' + filename);
204 
205                Object[] keys = null;
206                Object[] values = null;
207 
208                Collection<K> ks = filenameMap.getKeysForFilename(filename);
209                if (ks != null) {
210                    keys = ks.toArray();
211                    values = new Object[keys.length];
212                    for (int i = 0; i < keys.length; i++)
213                        values[i] = get(keys[i]);
214                }
215 
216                if (keys == null || keys.length == 0) {
217                    filenameMap.removeFilename(filename);
218                    return !file.exists() || file.delete();
219                }
220                out = new DataOutputStream(IOUtils.getOutputStream(file2));
221                out.writeUTF(KEYS_VALUES);
222                // take a synchronised copy of this.
223                writeObjects(out, (Object[]) keys);
224                writeObjects(out, (Object[]) values);
225                IOUtils.close(out);
226 
227                return IOUtils.rename(file, file2);
228            }
229        } catch (IOException e) {
230            LOG.error(Thread.currentThread().getName() + ": Unable to save " + dirname + " cannot create.", e);
231            return false;
232        } finally {
233            IOUtils.close(out);
234        }
235    }
236}

[all classes][org.jtoolkit.essence.data.impl]
EMMA 2.0.5312 (C) Vladimir Roubtsov