Db.java

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

Mutations

73

1.1
Location : <init>
Killed by : com.renomad.minum.utils.ActionQueueKillerTests
negated conditional → KILLED

87

1.1
Location : <init>
Killed by : com.renomad.minum.FunctionalTests.test_EdgeCase_IOExceptionThrown_WebFramework(com.renomad.minum.FunctionalTests)
removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → KILLED

2.2
Location : lambda$new$0
Killed by : none
removed call to com/renomad/minum/utils/IFileUtils::makeDirectory → TIMED_OUT

120

1.1
Location : write
Killed by : com.renomad.minum.database.DbTests
removed call to com/renomad/minum/database/Db::basicDataChecks → KILLED

123

1.1
Location : write
Killed by : none
negated conditional → TIMED_OUT

125

1.1
Location : write
Killed by : com.renomad.minum.FunctionalTests.testEndToEnd_Functional(com.renomad.minum.FunctionalTests)
removed call to com/renomad/minum/database/InspectableLock::lock → KILLED

128

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

131

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

132

1.1
Location : lambda$write$1
Killed by : com.renomad.minum.database.DbEngine2Tests
removed call to com/renomad/minum/database/Db::writeToDisk → KILLED

137

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

141

1.1
Location : write
Killed by : none
removed call to com/renomad/minum/database/InspectableLock::unlock → TIMED_OUT

154

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

156

1.1
Location : writeToDisk
Killed by : none
negated conditional → TIMED_OUT

157

1.1
Location : writeToDisk
Killed by : com.renomad.minum.FunctionalTests.testEndToEnd_Functional(com.renomad.minum.FunctionalTests)
Replaced long addition with subtraction → KILLED

2.2
Location : writeToDisk
Killed by : com.renomad.minum.FunctionalTests.testEndToEnd_Functional(com.renomad.minum.FunctionalTests)
removed call to com/renomad/minum/utils/IFileUtils::writeString → KILLED

174

1.1
Location : delete
Killed by : com.renomad.minum.FunctionalTests.testEndToEnd_Functional(com.renomad.minum.FunctionalTests)
removed call to com/renomad/minum/database/Db::basicDataChecks → KILLED

177

1.1
Location : delete
Killed by : com.renomad.minum.FunctionalTests.testEndToEnd_Functional(com.renomad.minum.FunctionalTests)
negated conditional → KILLED

179

1.1
Location : delete
Killed by : com.renomad.minum.FunctionalTests.testEndToEnd_Functional(com.renomad.minum.FunctionalTests)
removed call to com/renomad/minum/database/InspectableLock::lock → KILLED

182

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

187

1.1
Location : delete
Killed by : none
removed call to com/renomad/minum/queue/AbstractActionQueue::enqueue → TIMED_OUT

188

1.1
Location : lambda$delete$3
Killed by : none
removed call to com/renomad/minum/database/Db::deleteFromDisk → TIMED_OUT

193

1.1
Location : delete
Killed by : none
removed call to com/renomad/minum/database/InspectableLock::unlock → TIMED_OUT

202

1.1
Location : deleteFromDisk
Killed by : com.renomad.minum.FunctionalTests.testEndToEnd_Functional(com.renomad.minum.FunctionalTests)
negated conditional → KILLED

205

1.1
Location : deleteFromDisk
Killed by : none
removed call to com/renomad/minum/utils/IFileUtils::delete → TIMED_OUT

207

1.1
Location : deleteFromDisk
Killed by : none
negated conditional → TIMED_OUT

208

1.1
Location : deleteFromDisk
Killed by : com.renomad.minum.FunctionalTests.testEndToEnd_Functional(com.renomad.minum.FunctionalTests)
removed call to com/renomad/minum/utils/IFileUtils::writeString → KILLED

224

1.1
Location : loadDataFromDisk
Killed by : com.renomad.minum.FunctionalTests.test_EdgeCase_IOExceptionThrown_WebFramework(com.renomad.minum.FunctionalTests)
negated conditional → KILLED

225

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

228

1.1
Location : loadDataFromDisk
Killed by : com.renomad.minum.FunctionalTests.test_EdgeCase_BadRequest2(com.renomad.minum.FunctionalTests)
negated conditional → KILLED

233

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

241

1.1
Location : lambda$walkAndLoad$7
Killed by : com.renomad.minum.FunctionalTests.test_EdgeCase_IOExceptionThrown_WebFramework(com.renomad.minum.FunctionalTests)
negated conditional → KILLED

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

242

1.1
Location : lambda$walkAndLoad$7
Killed by : com.renomad.minum.database.DbTests
negated conditional → KILLED

245

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

256

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

259

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

268

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

282

1.1
Location : readAndDeserialize
Killed by : none
removed call to com/renomad/minum/database/Db::addToIndexes → TIMED_OUT

293

1.1
Location : values
Killed by : none
negated conditional → TIMED_OUT

295

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

307

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

309

1.1
Location : loadData
Killed by : com.renomad.minum.FunctionalTests.test_EdgeCase_IOExceptionThrown_WebFramework(com.renomad.minum.FunctionalTests)
negated conditional → KILLED

310

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

313

1.1
Location : loadData
Killed by : none
replaced return value with null for com/renomad/minum/database/Db::loadData → TIMED_OUT

317

1.1
Location : loadData
Killed by : none
removed call to java/util/concurrent/locks/ReentrantLock::unlock → TIMED_OUT

350

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

355

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

369

1.1
Location : getIndexedData
Killed by : none
negated conditional → TIMED_OUT

370

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

385

1.1
Location : stop
Killed by : com.renomad.minum.database.DbTests
removed call to com/renomad/minum/database/Db::stop → KILLED

394

1.1
Location : stop
Killed by : com.renomad.minum.database.DbEngine2Tests
removed call to com/renomad/minum/state/Context::removeFromPaths → KILLED

395

1.1
Location : stop
Killed by : com.renomad.minum.database.DbEngine2Tests
removed call to com/renomad/minum/queue/AbstractActionQueue::stop → KILLED

Active mutators

Tests examined


Report generated by PIT 1.17.0