Db.java

1
package com.renomad.minum.database;
2
3
import com.renomad.minum.queue.AbstractActionQueue;
4
import com.renomad.minum.queue.ActionQueue;
5
import com.renomad.minum.state.Context;
6
7
import java.io.BufferedReader;
8
import java.io.FileReader;
9
import java.io.IOException;
10
import java.nio.charset.StandardCharsets;
11
import java.nio.file.Files;
12
import java.nio.file.Path;
13
import java.util.Collection;
14
import java.util.Collections;
15
import java.util.concurrent.atomic.AtomicLong;
16
import java.util.concurrent.locks.ReentrantLock;
17
import java.util.function.Function;
18
19
import static com.renomad.minum.utils.Invariants.mustBeFalse;
20
import static com.renomad.minum.utils.Invariants.mustBeTrue;
21
22
/**
23
 * a memory-based disk-persisted database class.
24
 * @param <T> the type of data we'll be persisting (must extend from {@link DbData}
25
 */
26
public class Db<T extends DbData<?>> extends AbstractDb<T> {
27
28
    /**
29
     * The suffix we will apply to each database file
30
     */
31
    static final String DATABASE_FILE_SUFFIX = ".ddps";
32
    private final AbstractActionQueue actionQueue;
33
    private final ReentrantLock loadDataLock = new ReentrantLock();
34
35
    /**
36
     * The full path to the file that contains the most-recent index
37
     * for this data.  As we add new files, each gets its own index
38
     * value.  When we start the program, we use this to determine
39
     * where to start counting for new indexes.
40
     */
41
    private final Path fullPathForIndexFile;
42
43
    /**
44
     * An in-memory representation of the value of the current max index
45
     * that we store in index.ddps, in memory, so we can compare whether
46
     * we need to update the disk without checking the disk so often.
47
     */
48
    private long maxIndexOnDisk;
49
50
    boolean hasLoadedData;
51
52
    /**
53
     * Constructs an in-memory disk-persisted database.
54
     * Loading of data from disk happens at the first invocation of any command
55
     * changing or requesting data, such as {@link #write(DbData)}, {@link #delete(DbData)},
56
     * or {@link #values()}.  See the private method loadData() for details.
57
     * @param dbDirectory this uniquely names your database, and also sets the directory
58
     *                    name for this data.  The expected use case is to name this after
59
     *                    the data in question.  For example, "users", or "accounts".
60
     * @param context used to provide important state data to several components
61
     * @param instance an instance of the {@link DbData} object relevant for use in this database. Note
62
     *                 that each database (that is, each instance of this class), focuses on just one
63
     *                 data, which must be an implementation of {@link DbData}.
64
     */
65
    public Db(Path dbDirectory, Context context, T instance) {
66
        super(dbDirectory, context, instance);
67
        this.hasLoadedData = false;
68
        this.fullPathForIndexFile = dbDirectory.resolve("index" + DATABASE_FILE_SUFFIX);
69
        this.actionQueue = new ActionQueue("DatabaseWriter " + dbDirectory, context).initialize();
70
71 1 1. <init> : negated conditional → KILLED
        if (Files.exists(fullPathForIndexFile)) {
72
            long indexValue;
73
            try (var fileReader = new FileReader(fullPathForIndexFile.toFile(), StandardCharsets.UTF_8)) {
74
                try (BufferedReader br = new BufferedReader(fileReader)) {
75
                    String s = br.readLine();
76 1 1. <init> : negated conditional → KILLED
                    if (s == null) throw new DbException("index file at " + fullPathForIndexFile + " returned null when reading a line from it");
77
                    mustBeFalse(s.isBlank(), "Unless something is terribly broken, we expect a numeric value here");
78
                    String trim = s.trim();
79
                    indexValue = Long.parseLong(trim);
80
                }
81
            } catch (Exception e) {
82
                throw new DbException("Exception while reading "+fullPathForIndexFile+" in Db constructor", e);
83
            }
84
85
            this.index = new AtomicLong(indexValue);
86
87
        } else {
88
            this.index = new AtomicLong(1);
89
        }
90
91 2 1. lambda$new$0 : removed call to com/renomad/minum/utils/FileUtils::makeDirectory → KILLED
2. <init> : removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → KILLED
        actionQueue.enqueue("create directory" + dbDirectory, () -> fileUtils.makeDirectory(dbDirectory));
92
    }
93
94
    /**
95
     * Write data to the database.  Use an index of 0 to store new data, and a positive
96
     * non-zero value to update data.
97
     * <p><em>
98
     *     Example of adding new data to the database:
99
     * </p></em>
100
     * {@snippet :
101
     *          final var newSalt = StringUtils.generateSecureRandomString(10);
102
     *          final var hashedPassword = CryptoUtils.createPasswordHash(newPassword, newSalt);
103
     *          final var newUser = new User(0L, newUsername, hashedPassword, newSalt);
104
     *          userDb.write(newUser);
105
     * }
106
     * <p><em>
107
     *     Example of updating data:
108
     * </p></em>
109
     * {@snippet :
110
     *         // write the updated salted password to the database
111
     *         final var updatedUser = new User(
112
     *                 user().getIndex(),
113
     *                 user().getUsername(),
114
     *                 hashedPassword,
115
     *                 newSalt);
116
     *         userDb.write(updatedUser);
117
     * }
118
     *
119
     * @param newData the data we are writing
120
     * @return the data with its new index assigned.
121
     */
122
    @Override
123
    public T write(T newData) {
124 2 1. write : negated conditional → KILLED
2. write : changed conditional boundary → KILLED
        if (newData.getIndex() < 0) throw new DbException("Negative indexes are disallowed");
125
        // load data if needed
126 2 1. write : negated conditional → KILLED
2. write : removed call to com/renomad/minum/database/Db::loadData → KILLED
        if (!hasLoadedData) loadData();
127
128
        boolean newElementCreated = processDataIndex(newData);
129 1 1. write : removed call to com/renomad/minum/database/Db::writeToMemory → KILLED
        writeToMemory(newData, newElementCreated);
130
131
        // *** now handle the disk portion ***
132 2 1. write : removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → KILLED
2. lambda$write$1 : removed call to com/renomad/minum/database/Db::writeToDisk → KILLED
        actionQueue.enqueue("persist data to disk", () -> writeToDisk(newData));
133
134
        // returning the data at this point is the most convenient
135
        // way users will have access to the new index of the data.
136 1 1. write : replaced return value with null for com/renomad/minum/database/Db::write → KILLED
        return newData;
137
    }
138
139
    private void writeToDisk(T newData) {
140
        final Path fullPath = dbDirectory.resolve(newData.getIndex() + DATABASE_FILE_SUFFIX);
141
        logger.logTrace(() -> String.format("writing data to %s", fullPath));
142
        String serializedData = newData.serialize();
143
        mustBeFalse(serializedData == null || serializedData.isBlank(),
144
                "the serialized form of data must not be blank. " +
145
                        "Is the serialization code written properly? Our datatype: " + emptyInstance);
146 1 1. writeToDisk : removed call to com/renomad/minum/utils/FileUtils::writeString → KILLED
        fileUtils.writeString(fullPath, serializedData);
147 2 1. writeToDisk : negated conditional → KILLED
2. writeToDisk : changed conditional boundary → KILLED
        if (maxIndexOnDisk < index.get()) {
148
            maxIndexOnDisk = index.get();
149 1 1. writeToDisk : removed call to com/renomad/minum/utils/FileUtils::writeString → TIMED_OUT
            fileUtils.writeString(fullPathForIndexFile, String.valueOf(maxIndexOnDisk));
150
        }
151
    }
152
153
    /**
154
     * Delete data
155
     * <p><em>Example:</p></em>
156
     * {@snippet :
157
     *      userDb.delete(user);
158
     * }
159
     * @param dataToDelete the data we are serializing and writing
160
     */
161
    @Override
162
    public void delete(T dataToDelete) {
163
        // load data if needed
164 2 1. delete : negated conditional → KILLED
2. delete : removed call to com/renomad/minum/database/Db::loadData → KILLED
        if (!hasLoadedData) loadData();
165
166
        // deal with the in-memory portion
167 1 1. delete : removed call to com/renomad/minum/database/Db::deleteFromMemory → KILLED
        deleteFromMemory(dataToDelete);
168
169
        // now handle the disk portion
170 2 1. lambda$delete$3 : removed call to com/renomad/minum/database/Db::deleteFromDisk → KILLED
2. delete : removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → KILLED
        actionQueue.enqueue("delete data from disk", () -> deleteFromDisk(dataToDelete));
171
    }
172
173
    private void deleteFromDisk(T dataToDelete) {
174
        final Path fullPath = dbDirectory.resolve(dataToDelete.getIndex() + DATABASE_FILE_SUFFIX);
175
        logger.logTrace(() -> String.format("deleting data at %s", fullPath));
176
        try {
177 1 1. deleteFromDisk : negated conditional → KILLED
            if (!fullPath.toFile().exists()) {
178
                throw new DbException(fullPath + " must already exist before deletion");
179
            }
180 1 1. deleteFromDisk : removed call to java/nio/file/Files::delete → KILLED
            Files.delete(fullPath);
181 2 1. deleteFromDisk : changed conditional boundary → KILLED
2. deleteFromDisk : negated conditional → KILLED
            if (maxIndexOnDisk > index.get()) {
182
                maxIndexOnDisk = index.get();
183 1 1. deleteFromDisk : removed call to com/renomad/minum/utils/FileUtils::writeString → KILLED
                fileUtils.writeString(fullPathForIndexFile, String.valueOf(maxIndexOnDisk));
184
185
            }
186
        } catch (Exception ex) {
187
            logger.logAsyncError(() -> "failed to delete file " + fullPath + " during deleteOnDisk. Exception: " + ex);
188
        }
189
    }
190
191
    /**
192
     * Grabs all the data from disk and returns it as a list.  This
193
     * method is run by various programs when the system first loads.
194
     */
195
    private void loadDataFromDisk() throws IOException {
196
        logger.logDebug(() -> "Loading data from disk. Db classic. Directory: " + dbDirectory);
197
198
        // check if the folder has content for a DbEngine2 database, meaning we
199
        // need to convert it back to the classic DB file structure.
200 1 1. loadDataFromDisk : negated conditional → KILLED
        if (Files.exists(dbDirectory.resolve("currentAppendLog"))) {
201 1 1. loadDataFromDisk : removed call to com/renomad/minum/database/DbFileConverter::convertFolderStructureToDbClassic → KILLED
            new DbFileConverter(context, dbDirectory).convertFolderStructureToDbClassic();
202
        }
203
204 1 1. loadDataFromDisk : negated conditional → KILLED
        if (! Files.exists(dbDirectory)) {
205
            logger.logDebug(() -> dbDirectory + " directory missing, adding nothing to the data list");
206
            return;
207
        }
208
209 1 1. loadDataFromDisk : removed call to com/renomad/minum/database/Db::walkAndLoad → KILLED
        walkAndLoad(dbDirectory);
210
    }
211
212
    void walkAndLoad(Path dbDirectory) {
213
        // walk through all the files in this directory, collecting
214
        // all regular files (non-subdirectories) except for index.ddps
215
        try (final var pathStream = Files.walk(dbDirectory)) {
216
            final var listOfFiles = pathStream.filter(path ->
217 2 1. lambda$walkAndLoad$8 : negated conditional → KILLED
2. lambda$walkAndLoad$8 : replaced boolean return with true for com/renomad/minum/database/Db::lambda$walkAndLoad$8 → KILLED
                        Files.isRegularFile(path) &&
218 1 1. lambda$walkAndLoad$8 : negated conditional → KILLED
                        !path.getFileName().toString().startsWith("index")
219
            ).toList();
220
            for (Path p : listOfFiles) {
221 1 1. walkAndLoad : removed call to com/renomad/minum/database/Db::readAndDeserialize → KILLED
                readAndDeserialize(p);
222
            }
223
        } catch (IOException e) {
224
            throw new DbException(e);
225
        }
226
    }
227
228
    /**
229
     * Carry out the process of reading data files into our in-memory structure
230
     * @param p the path of a particular file
231
     */
232
    void readAndDeserialize(Path p) throws IOException {
233
        Path fileName = p.getFileName();
234 1 1. readAndDeserialize : negated conditional → KILLED
        if (fileName == null) throw new DbException("At readAndDeserialize, path " + p + " returned a null filename");
235
        String filename = fileName.toString();
236
        int startOfSuffixIndex = filename.indexOf('.');
237 1 1. readAndDeserialize : negated conditional → KILLED
        if(startOfSuffixIndex == -1) {
238
            throw new DbException("the files must have a ddps suffix, like 1.ddps.  filename: " + filename);
239
        }
240
        String fileContents = Files.readString(p);
241 1 1. readAndDeserialize : negated conditional → KILLED
        if (fileContents.isBlank()) {
242
            logger.logDebug( () -> fileName + " file exists but empty, skipping");
243
        } else {
244
            try {
245
                @SuppressWarnings("unchecked")
246
                T deserializedData = (T) emptyInstance.deserialize(fileContents);
247
                mustBeTrue(deserializedData != null, "deserialization of " + emptyInstance +
248
                        " resulted in a null value. Was the serialization method implemented properly?");
249
                int fileNameIdentifier = Integer.parseInt(filename.substring(0, startOfSuffixIndex));
250
                mustBeTrue(deserializedData.getIndex() == fileNameIdentifier,
251
                        "The filename must correspond to the data's index. e.g. 1.ddps must have an id of 1");
252
253
                // put the data into the in-memory data structure
254
                data.put(deserializedData.getIndex(), deserializedData);
255 1 1. readAndDeserialize : removed call to com/renomad/minum/database/Db::addToIndexes → KILLED
                addToIndexes(deserializedData);
256
257
            } catch (Exception e) {
258
                throw new DbException("Failed to deserialize "+ p +" with data (\""+fileContents+"\"). Caused by: " + e);
259
            }
260
        }
261
    }
262
263
    @Override
264
    public Collection<T> values() {
265
        // load data if needed
266 2 1. values : removed call to com/renomad/minum/database/Db::loadData → TIMED_OUT
2. values : negated conditional → KILLED
        if (!hasLoadedData) loadData();
267
268 1 1. values : replaced return value with Collections.emptyList for com/renomad/minum/database/Db::values → KILLED
        return Collections.unmodifiableCollection(data.values());
269
    }
270
271
    /**
272
     * This is what loads the data from disk the
273
     * first time someone needs it.  Because it is
274
     * locked, only one thread can enter at
275
     * a time.  The first one in will load the data,
276
     * and the second will encounter a branch which skips loading.
277
     */
278
    @Override
279
    public void loadData() {
280 1 1. loadData : removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED
        loadDataLock.lock(); // block threads here if multiple are trying to get in - only one gets in at a time
281
        try {
282 1 1. loadData : negated conditional → KILLED
            if (!hasLoadedData) {
283 1 1. loadData : removed call to com/renomad/minum/database/Db::loadDataFromDisk → KILLED
                loadDataFromDisk();
284
            }
285
            hasLoadedData = true;
286
        } catch (Exception ex) {
287
            throw new DbException("Failed to load data from disk.", ex);
288
        } finally {
289 1 1. loadData : removed call to java/util/concurrent/locks/ReentrantLock::unlock → KILLED
            loadDataLock.unlock();
290
        }
291
    }
292
293
    /**
294
     * Register an index in the database for higher performance data access.
295
     * <p>
296
     *     This command should be run immediately after database declaration,
297
     *     or more specifically, before any data is loaded from disk. Otherwise,
298
     *     it would be possible to skip indexing that data.
299
     * </p>
300
     * <br>
301
     * Example:
302
     *  {@snippet :
303
     *           final var myDatabase = context.getDb("photos", Photograph.EMPTY);
304
     *           myDatabase.registerIndex("url", photo -> photo.getUrl());
305
     *  }
306
     * @param indexName a string used to distinguish this index.  This string will be used again
307
     *                  when requesting data in a method like {@link #getIndexedData} or {@link #findExactlyOne}
308
     * @param keyObtainingFunction a function which obtains data from the data in this database, used
309
     *                             to partition the data into groups (potentially up to a 1-to-1 correspondence
310
     *                             between id and object)
311
     * @return true if the registration succeeded
312
     * @throws DbException if the parameters are not entered properly, if the index has already
313
     * been registered, or if the data has already been loaded. It is necessary that
314
     * this is run immediately after declaring the database. To explain further: the data is not
315
     * actually loaded until the first time it is needed, such as running a write or delete, or
316
     * if the {@link #loadDataFromDisk()} method is run.  Creating an index map for the data that
317
     * is read from disk only occurs once, at data load time.  Thus, it is crucial that the
318
     * registerIndex command is run before any data is loaded.
319
     */
320
    @Override
321
    public boolean registerIndex(String indexName, Function<T, String> keyObtainingFunction) {
322 1 1. registerIndex : negated conditional → KILLED
        if (hasLoadedData) {
323
            throw new DbException("This method must be run before the database loads data from disk.  Typically, " +
324
                    "it should be run immediately after the database is created.  See this method's documentation");
325
        }
326 2 1. registerIndex : replaced boolean return with true for com/renomad/minum/database/Db::registerIndex → SURVIVED
2. registerIndex : replaced boolean return with false for com/renomad/minum/database/Db::registerIndex → KILLED
        return super.registerIndex(indexName, keyObtainingFunction);
327
    }
328
329
    /**
330
     * Given the name of a registered index (see {@link #registerIndex(String, Function)}),
331
     * use the key to find the collection of data that matches it.
332
     * @param indexName the name of an index
333
     * @param key a string value that matches a partition calculated from the partition
334
     *            function provided to {@link #registerIndex(String, Function)}
335
     * @return a collection of data, an empty collection if nothing found
336
     */
337
    @Override
338
    public Collection<T> getIndexedData(String indexName, String key) {
339
        // load data if needed
340 2 1. getIndexedData : negated conditional → KILLED
2. getIndexedData : removed call to com/renomad/minum/database/Db::loadData → KILLED
        if (!hasLoadedData) loadData();
341 1 1. getIndexedData : replaced return value with Collections.emptyList for com/renomad/minum/database/Db::getIndexedData → KILLED
        return super.getIndexedData(indexName, key);
342
    }
343
344
    /**
345
     * This function will stop the minum.database persistence cleanly.
346
     * <p>
347
     * In order to do this, we need to wait for our threads
348
     * to finish their work.  In particular, we
349
     * have offloaded our file writes to [actionQueue], which
350
     * has an internal thread for serializing all actions
351
     * on our minum.database
352
     * </p>
353
     */
354
    @Override
355
    public void stop() {
356 1 1. stop : removed call to com/renomad/minum/queue/AbstractActionQueue::stop → KILLED
        actionQueue.stop();
357
    }
358
359
    /**
360
     * Similar to {@link #stop()} but gives more control over how long
361
     * we'll wait before crashing it closed.  See {@link ActionQueue#stop(int, int)}
362
     */
363
    @Override
364
    public void stop(int count, int sleepTime) {
365 1 1. stop : removed call to com/renomad/minum/queue/AbstractActionQueue::stop → KILLED
        actionQueue.stop(count, sleepTime);
366
    }
367
368
}

Mutations

71

1.1
Location : <init>
Killed by : com.renomad.minum.database.DbTests.testWalkAndLoad_EdgeCase_FolderMissing(com.renomad.minum.database.DbTests)
negated conditional → KILLED

76

1.1
Location : <init>
Killed by : com.renomad.minum.database.DbTests.test_firstActionIsFindExactlyOne(com.renomad.minum.database.DbTests)
negated conditional → KILLED

91

1.1
Location : lambda$new$0
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCases_2(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/utils/FileUtils::makeDirectory → KILLED

2.2
Location : <init>
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCases_2(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → KILLED

124

1.1
Location : write
Killed by : com.renomad.minum.database.DbTests.testSearchUtils_ShouldAccommodateUsingIndexes(com.renomad.minum.database.DbTests)
negated conditional → KILLED

2.2
Location : write
Killed by : com.renomad.minum.database.DbTests.testSearchUtils_ShouldAccommodateUsingIndexes(com.renomad.minum.database.DbTests)
changed conditional boundary → KILLED

126

1.1
Location : write
Killed by : com.renomad.minum.database.DbTests.test_EdgeCase_RegisteringIndexTooLate(com.renomad.minum.database.DbTests)
negated conditional → KILLED

2.2
Location : write
Killed by : com.renomad.minum.database.DbTests.test_EdgeCase_RegisteringIndexTooLate(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::loadData → KILLED

129

1.1
Location : write
Killed by : com.renomad.minum.database.DbTests.testSearchUtils_ShouldAccommodateUsingIndexes(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::writeToMemory → KILLED

132

1.1
Location : write
Killed by : com.renomad.minum.database.DbTests.testDeserializerComplaints(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → KILLED

2.2
Location : lambda$write$1
Killed by : com.renomad.minum.database.DbTests.testDeserializerComplaints(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::writeToDisk → KILLED

136

1.1
Location : write
Killed by : com.renomad.minum.database.DbTests.testSearchUtils_ShouldAccommodateUsingIndexes(com.renomad.minum.database.DbTests)
replaced return value with null for com/renomad/minum/database/Db::write → KILLED

146

1.1
Location : writeToDisk
Killed by : com.renomad.minum.database.DbTests.testDeserializerComplaints(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/utils/FileUtils::writeString → KILLED

147

1.1
Location : writeToDisk
Killed by : com.renomad.minum.database.DbTests.test_Locking_2(com.renomad.minum.database.DbTests)
negated conditional → KILLED

2.2
Location : writeToDisk
Killed by : com.renomad.minum.database.DbTests.test_Locking(com.renomad.minum.database.DbTests)
changed conditional boundary → KILLED

149

1.1
Location : writeToDisk
Killed by : none
removed call to com/renomad/minum/utils/FileUtils::writeString → TIMED_OUT

164

1.1
Location : delete
Killed by : com.renomad.minum.database.DbTests.test_Locking(com.renomad.minum.database.DbTests)
negated conditional → KILLED

2.2
Location : delete
Killed by : com.renomad.minum.database.DbTests.test_Db_Write_and_Read(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::loadData → KILLED

167

1.1
Location : delete
Killed by : com.renomad.minum.database.DbTests.testIndexesOnPartitionedData(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::deleteFromMemory → KILLED

170

1.1
Location : lambda$delete$3
Killed by : com.renomad.minum.database.DbTests.test_Locking(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::deleteFromDisk → KILLED

2.2
Location : delete
Killed by : com.renomad.minum.database.DbTests.test_Locking(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → KILLED

177

1.1
Location : deleteFromDisk
Killed by : com.renomad.minum.database.DbTests.test_Locking(com.renomad.minum.database.DbTests)
negated conditional → KILLED

180

1.1
Location : deleteFromDisk
Killed by : com.renomad.minum.database.DbTests.test_Locking(com.renomad.minum.database.DbTests)
removed call to java/nio/file/Files::delete → KILLED

181

1.1
Location : deleteFromDisk
Killed by : com.renomad.minum.database.DbTests.test_Locking(com.renomad.minum.database.DbTests)
changed conditional boundary → KILLED

2.2
Location : deleteFromDisk
Killed by : com.renomad.minum.database.DbTests.test_Locking_2(com.renomad.minum.database.DbTests)
negated conditional → KILLED

183

1.1
Location : deleteFromDisk
Killed by : com.renomad.minum.database.DbTests.test_GeneralCapability(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/utils/FileUtils::writeString → KILLED

200

1.1
Location : loadDataFromDisk
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCase3(com.renomad.minum.database.DbTests)
negated conditional → KILLED

201

1.1
Location : loadDataFromDisk
Killed by : com.renomad.minum.database.DbTests.test_ConvertingDatabase_DbEngine2_To_DbClassic(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/DbFileConverter::convertFolderStructureToDbClassic → KILLED

204

1.1
Location : loadDataFromDisk
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCases_2(com.renomad.minum.database.DbTests)
negated conditional → KILLED

209

1.1
Location : loadDataFromDisk
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCases_2(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::walkAndLoad → KILLED

217

1.1
Location : lambda$walkAndLoad$8
Killed by : com.renomad.minum.database.DbTests.testSearchUtility_EdgeCase_NoIndexRegistered(com.renomad.minum.database.DbTests)
negated conditional → KILLED

2.2
Location : lambda$walkAndLoad$8
Killed by : com.renomad.minum.database.DbTests.testSearchUtility_EdgeCase_NoIndexRegistered(com.renomad.minum.database.DbTests)
replaced boolean return with true for com/renomad/minum/database/Db::lambda$walkAndLoad$8 → KILLED

218

1.1
Location : lambda$walkAndLoad$8
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCases_2(com.renomad.minum.database.DbTests)
negated conditional → KILLED

221

1.1
Location : walkAndLoad
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCases_2(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::readAndDeserialize → KILLED

234

1.1
Location : readAndDeserialize
Killed by : com.renomad.minum.database.DbTests.testReadAndDeserialize_nullFilename(com.renomad.minum.database.DbTests)
negated conditional → KILLED

237

1.1
Location : readAndDeserialize
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCases(com.renomad.minum.database.DbTests)
negated conditional → KILLED

241

1.1
Location : readAndDeserialize
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCases_2(com.renomad.minum.database.DbTests)
negated conditional → KILLED

255

1.1
Location : readAndDeserialize
Killed by : com.renomad.minum.database.DbTests.test_firstActionIsFindExactlyOne(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::addToIndexes → KILLED

266

1.1
Location : values
Killed by : com.renomad.minum.database.DbTests.test_ConvertingDatabase_DbEngine2_To_DbClassic(com.renomad.minum.database.DbTests)
negated conditional → KILLED

2.2
Location : values
Killed by : none
removed call to com/renomad/minum/database/Db::loadData → TIMED_OUT

268

1.1
Location : values
Killed by : com.renomad.minum.database.DbTests.testIndexSpeedDifference(com.renomad.minum.database.DbTests)
replaced return value with Collections.emptyList for com/renomad/minum/database/Db::values → KILLED

280

1.1
Location : loadData
Killed by : com.renomad.minum.database.DbTests.testSearchUtility_EdgeCase_NoIndexRegistered(com.renomad.minum.database.DbTests)
removed call to java/util/concurrent/locks/ReentrantLock::lock → KILLED

282

1.1
Location : loadData
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCases_2(com.renomad.minum.database.DbTests)
negated conditional → KILLED

283

1.1
Location : loadData
Killed by : com.renomad.minum.database.DbTests.test_Deserialization_EdgeCases_2(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::loadDataFromDisk → KILLED

289

1.1
Location : loadData
Killed by : com.renomad.minum.database.DbTests.test_Locking(com.renomad.minum.database.DbTests)
removed call to java/util/concurrent/locks/ReentrantLock::unlock → KILLED

322

1.1
Location : registerIndex
Killed by : com.renomad.minum.database.DbTests.testIndex_EdgeCase_MultipleIndexes(com.renomad.minum.database.DbTests)
negated conditional → KILLED

326

1.1
Location : registerIndex
Killed by : com.renomad.minum.database.DbTests.testIndex_EdgeCase_MultipleIndexes(com.renomad.minum.database.DbTests)
replaced boolean return with false for com/renomad/minum/database/Db::registerIndex → KILLED

2.2
Location : registerIndex
Killed by : none
replaced boolean return with true for com/renomad/minum/database/Db::registerIndex → SURVIVED
Covering tests

340

1.1
Location : getIndexedData
Killed by : com.renomad.minum.database.DbTests.test_firstActionIsFindExactlyOne(com.renomad.minum.database.DbTests)
negated conditional → KILLED

2.2
Location : getIndexedData
Killed by : com.renomad.minum.database.DbTests.test_firstActionIsFindExactlyOne(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/database/Db::loadData → KILLED

341

1.1
Location : getIndexedData
Killed by : com.renomad.minum.database.DbTests.testSearchUtils_ShouldAccommodateUsingIndexes(com.renomad.minum.database.DbTests)
replaced return value with Collections.emptyList for com/renomad/minum/database/Db::getIndexedData → KILLED

356

1.1
Location : stop
Killed by : com.renomad.minum.database.DbTests.testStopping(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/queue/AbstractActionQueue::stop → KILLED

365

1.1
Location : stop
Killed by : com.renomad.minum.database.DbTests.testStopping2(com.renomad.minum.database.DbTests)
removed call to com/renomad/minum/queue/AbstractActionQueue::stop → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0