This repository has been archived by the owner on Mar 3, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 78
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Солнышко Ксения, ИТМО ФИТиП, M3332, Expiration (#300)
Co-authored-by: Vadim Tsesko <incubos@users.noreply.github.com> Co-authored-by: Alexey Shik <58121508+AlexeyShik@users.noreply.github.com>
- Loading branch information
1 parent
94e5d9b
commit 913870a
Showing
8 changed files
with
795 additions
and
125 deletions.
There are no files selected for viewing
11 changes: 11 additions & 0 deletions
11
src/main/java/ru/vk/itmo/solnyshkoksenia/DaoException.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package ru.vk.itmo.solnyshkoksenia; | ||
|
||
public class DaoException extends RuntimeException { | ||
public DaoException(String message) { | ||
super(message); | ||
} | ||
|
||
public DaoException(String message, Throwable cause) { | ||
super(message, cause); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
10 changes: 10 additions & 0 deletions
10
src/main/java/ru/vk/itmo/solnyshkoksenia/EntryExtended.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
package ru.vk.itmo.solnyshkoksenia; | ||
|
||
import ru.vk.itmo.Entry; | ||
|
||
public record EntryExtended<Data>(Data key, Data value, Data expiration) implements Entry<Data> { | ||
@Override | ||
public String toString() { | ||
return "{" + key + ":" + value + ":" + expiration + "}"; | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,148 @@ | ||
package ru.vk.itmo.solnyshkoksenia; | ||
|
||
import ru.vk.itmo.Config; | ||
import ru.vk.itmo.Entry; | ||
import ru.vk.itmo.solnyshkoksenia.storage.DiskStorage; | ||
|
||
import java.io.IOException; | ||
import java.lang.foreign.MemorySegment; | ||
import java.lang.foreign.ValueLayout; | ||
import java.util.Collections; | ||
import java.util.Comparator; | ||
import java.util.Iterator; | ||
import java.util.NavigableMap; | ||
import java.util.concurrent.ConcurrentSkipListMap; | ||
import java.util.concurrent.atomic.AtomicBoolean; | ||
import java.util.concurrent.atomic.AtomicLong; | ||
|
||
public class State { | ||
private static final Comparator<MemorySegment> comparator = new MemorySegmentComparator(); | ||
protected final Config config; | ||
protected final NavigableMap<MemorySegment, EntryExtended<MemorySegment>> storage; | ||
protected final NavigableMap<MemorySegment, EntryExtended<MemorySegment>> flushingStorage; | ||
protected final DiskStorage diskStorage; | ||
private final AtomicLong storageByteSize = new AtomicLong(); | ||
private final AtomicBoolean isClosed = new AtomicBoolean(); | ||
private final AtomicBoolean overflow = new AtomicBoolean(); | ||
|
||
public State(Config config, | ||
NavigableMap<MemorySegment, EntryExtended<MemorySegment>> storage, | ||
NavigableMap<MemorySegment, EntryExtended<MemorySegment>> flushingStorage, | ||
DiskStorage diskStorage) { | ||
this.config = config; | ||
this.storage = storage; | ||
this.flushingStorage = flushingStorage; | ||
this.diskStorage = diskStorage; | ||
} | ||
|
||
public State(Config config, | ||
DiskStorage diskStorage) { | ||
this.config = config; | ||
this.storage = new ConcurrentSkipListMap<>(comparator); | ||
this.flushingStorage = new ConcurrentSkipListMap<>(comparator); | ||
this.diskStorage = diskStorage; | ||
} | ||
|
||
public void putInMemory(Entry<MemorySegment> entry, Long ttl) { | ||
MemorySegment expiration = null; | ||
if (ttl != null) { | ||
long[] ar = {System.currentTimeMillis() + ttl}; | ||
expiration = MemorySegment.ofArray(ar); | ||
} | ||
EntryExtended<MemorySegment> entryExtended = new EntryExtended<>(entry.key(), entry.value(), expiration); | ||
EntryExtended<MemorySegment> previousEntry = storage.put(entryExtended.key(), entryExtended); | ||
|
||
if (previousEntry != null) { | ||
storageByteSize.addAndGet(-getSize(previousEntry)); | ||
} | ||
|
||
if (storageByteSize.addAndGet(getSize(entryExtended)) > config.flushThresholdBytes()) { | ||
overflow.set(true); | ||
} | ||
} | ||
|
||
public void save() throws IOException { | ||
diskStorage.save(storage.values()); | ||
} | ||
|
||
private static long getSize(EntryExtended<MemorySegment> entry) { | ||
long valueSize = entry.value() == null ? 0 : entry.value().byteSize(); | ||
long expirationSize = entry.expiration() == null ? 0 : entry.expiration().byteSize(); | ||
return Long.BYTES + entry.key().byteSize() + Long.BYTES + valueSize + Long.BYTES + expirationSize; | ||
} | ||
|
||
public State checkAndGet() { | ||
if (isClosed.get()) { | ||
throw new DaoException("Dao is already closed"); | ||
} | ||
return this; | ||
} | ||
|
||
public boolean isClosed() { | ||
return isClosed.get(); | ||
} | ||
|
||
public boolean isOverflowed() { | ||
return overflow.get(); | ||
} | ||
|
||
public boolean isFlushing() { | ||
return !flushingStorage.isEmpty(); | ||
} | ||
|
||
public State moveStorage() { | ||
return new State(config, new ConcurrentSkipListMap<>(comparator), storage, diskStorage); | ||
} | ||
|
||
public void flush() throws IOException { | ||
diskStorage.save(flushingStorage.values()); | ||
} | ||
|
||
public State close() { | ||
isClosed.set(true); | ||
return this; | ||
} | ||
|
||
public Entry<MemorySegment> get(MemorySegment key, Comparator<MemorySegment> comparator) { | ||
EntryExtended<MemorySegment> entry = storage.get(key); | ||
if (isValidEntry(entry)) { | ||
return entry.value() == null ? null : entry; | ||
} | ||
|
||
entry = flushingStorage.get(key); | ||
if (isValidEntry(entry)) { | ||
return entry.value() == null ? null : entry; | ||
} | ||
|
||
Iterator<EntryExtended<MemorySegment>> iterator = diskStorage.range(Collections.emptyIterator(), key, null); | ||
|
||
if (!iterator.hasNext()) { | ||
return null; | ||
} | ||
EntryExtended<MemorySegment> next = iterator.next(); | ||
if (comparator.compare(next.key(), key) == 0 && isValidEntry(next)) { | ||
return next; | ||
} | ||
return null; | ||
} | ||
|
||
private boolean isValidEntry(EntryExtended<MemorySegment> entry) { | ||
return entry != null && (entry.expiration() == null | ||
|| entry.expiration().toArray(ValueLayout.JAVA_LONG_UNALIGNED)[0] > System.currentTimeMillis()); | ||
} | ||
|
||
protected Iterator<EntryExtended<MemorySegment>> getInMemory( | ||
NavigableMap<MemorySegment, EntryExtended<MemorySegment>> memory, | ||
MemorySegment from, MemorySegment to) { | ||
if (from == null && to == null) { | ||
return memory.values().iterator(); | ||
} | ||
if (from == null) { | ||
return memory.headMap(to).values().iterator(); | ||
} | ||
if (to == null) { | ||
return memory.tailMap(from).values().iterator(); | ||
} | ||
return memory.subMap(from, to).values().iterator(); | ||
} | ||
} |
Oops, something went wrong.