New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
g595.Manucharyan.task3 #279
Changes from 7 commits
0866a60
552d60a
3b50057
da7781b
10c6e3d
2f58fa2
a9c4c95
a9f1fc8
f530f07
83ecff4
6446586
181536f
af9170b
a9a52c0
f95b2d3
a85598c
0ccfc8a
e81d659
81e49f0
12319c8
b1b8e2b
e328d85
8722b58
89423e5
6c53bd8
eacb2e4
edcfe73
47dde1d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package ru.mipt.java2016.homework.g595.manucharyan.task3; | ||
|
||
import java.io.IOException; | ||
import java.io.RandomAccessFile; | ||
|
||
/** | ||
* @author Vardan Manucharyan | ||
* @since 30.10.16 | ||
*/ | ||
public class ConcreteStrategyDoubleRandomAccess implements SerializationStrategyRandomAccess<Double> { | ||
@Override | ||
public void serializeToFile(Double value, RandomAccessFile output) throws IOException { | ||
output.writeDouble(value); | ||
} | ||
|
||
@Override | ||
public Double deserializeFromFile(RandomAccessFile input) throws IOException { | ||
return input.readDouble(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
package ru.mipt.java2016.homework.g595.manucharyan.task3; | ||
|
||
import java.io.IOException; | ||
import java.io.RandomAccessFile; | ||
|
||
/** | ||
* @author Vardan Manucharyan | ||
* @since 30.10.16 | ||
*/ | ||
public class ConcreteStrategyIntegerRandomAccess implements SerializationStrategyRandomAccess<Integer> { | ||
@Override | ||
public void serializeToFile(Integer value, RandomAccessFile output) throws IOException { | ||
output.writeInt(value); | ||
} | ||
|
||
@Override | ||
public Integer deserializeFromFile(RandomAccessFile input) throws IOException { | ||
return input.readInt(); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,33 @@ | ||
package ru.mipt.java2016.homework.g595.manucharyan.task3; | ||
|
||
import java.io.IOException; | ||
import java.io.RandomAccessFile; | ||
|
||
/** | ||
* @author Vardan Manucharyan | ||
* @since 30.10.16 | ||
*/ | ||
public class ConcreteStrategyStringRandomAccess implements SerializationStrategyRandomAccess<String> { | ||
@Override | ||
public void serializeToFile(String value, RandomAccessFile output) throws IOException { | ||
writeString(output, value); | ||
} | ||
|
||
@Override | ||
public String deserializeFromFile(RandomAccessFile input) throws IOException { | ||
return readString(input); | ||
} | ||
|
||
//serializing functions | ||
public static void writeString(RandomAccessFile output, String string) throws IOException { | ||
output.writeInt(string.length()); | ||
output.write(string.getBytes("UTF-8")); | ||
} | ||
|
||
public static String readString(RandomAccessFile input) throws IOException { | ||
int len = input.readInt(); | ||
byte[] bytes = new byte[len]; | ||
input.read(bytes); | ||
return new String(bytes); | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
package ru.mipt.java2016.homework.g595.manucharyan.task3; | ||
|
||
import java.io.File; | ||
import java.io.IOException; | ||
import java.io.RandomAccessFile; | ||
import java.util.HashMap; | ||
import java.util.Iterator; | ||
|
||
import ru.mipt.java2016.homework.base.task2.KeyValueStorage; | ||
|
||
import static java.lang.Math.max; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Здесь в последних двух абзацах довольно коротко поясняют за статик импорт, и когда его нужно/не нужно использовать. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. просто, когда я написал max() он предложил подключить это (там было несколько вариантов), я просто нажал enter и забил) |
||
|
||
/** | ||
* @author Vardan Manucharyan | ||
* @since 20.11.2016. | ||
*/ | ||
public class OptimisedKeyValueStorage<K, V> implements KeyValueStorage<K, V> { | ||
|
||
private static final long MAX_CACHE_SIZE = 100L; | ||
|
||
private SerializationStrategyRandomAccess<K> keySerializationStrategy; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. да, врятли... |
||
private SerializationStrategyRandomAccess<V> valueSerializationStrategy; | ||
|
||
//consist keys and offsets(the pair of begin and length) | ||
private HashMap<K, Long> base = new HashMap<>(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Лучше тип переменной сделать There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Странно, у меня так же было и во втором задании... |
||
private HashMap<K, V> cache = new HashMap<>(); | ||
|
||
private long maxOffset; | ||
private final String pathname; | ||
private RandomAccessFile storage; | ||
private final String storageName = "storage.txt"; | ||
private RandomAccessFile mapStorage; | ||
private final String mapStorageName = "mapStorage.txt"; | ||
|
||
private File mutexFile; // для многопоточности | ||
private boolean isClosed; | ||
|
||
public OptimisedKeyValueStorage(SerializationStrategyRandomAccess<K> keySerializationStrategy, | ||
SerializationStrategyRandomAccess<V> valueSerializaionStrategy, | ||
String path) throws IOException { | ||
|
||
this.keySerializationStrategy = keySerializationStrategy; | ||
this.valueSerializationStrategy = valueSerializaionStrategy; | ||
maxOffset = 0L; | ||
pathname = path; | ||
|
||
mutexFile = new File(pathname, "Mutex"); | ||
if (!mutexFile.createNewFile()) { | ||
throw new RuntimeException("Can't synchronize!"); | ||
} | ||
|
||
File directory = new File(pathname); | ||
if (!directory.isDirectory()) { | ||
throw new RuntimeException("wrong path"); | ||
} | ||
|
||
File file = new File(pathname, storageName); | ||
storage = new RandomAccessFile(file, "rw"); | ||
|
||
File file2 = new File(path, mapStorageName); | ||
mapStorage = new RandomAccessFile(file2, "rw"); | ||
|
||
if (file.exists() && file2.exists()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. При создании There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Поправил |
||
uploadDataFromStorage(); | ||
} else if (!file.createNewFile() || file2.createNewFile()) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. true if the named file does not exist and was successfully created; false if the named file already exists. Если файл не удалось создать, то должно вернуться false, нет? Ветвление здесь вот зачем: есть два варианта, файлы уже есть, тогда загружаем их. Если же их нет, но и создать их не получилось, то что-то пошло не так There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Давай так. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ок |
||
throw new RuntimeException("Can't create a storage!"); | ||
} | ||
|
||
isClosed = false; | ||
} | ||
|
||
/** | ||
* Возвращает значение для данного ключа, если оно есть в хранилище. | ||
* Иначе возвращает null. | ||
*/ | ||
@Override | ||
public synchronized V read(K key) { | ||
if (!exists(key)) { | ||
return null; | ||
} else { | ||
try { | ||
if (cache.get(key) != null) { | ||
return cache.get(key); | ||
} | ||
|
||
Long offset = base.get(key); | ||
storage.seek(offset); | ||
return valueSerializationStrategy.deserializeFromFile(storage); | ||
} catch (Exception exception) { | ||
throw new RuntimeException("Can't read from storage"); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Возвращает true, если данный ключ есть в хранилище | ||
*/ | ||
@Override | ||
public boolean exists(K key) { | ||
if (isClosed) { | ||
return false; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Тут бы There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. У меня в close() и не было ничего) А так да, мне приходила эта идея в голову, но я забил) |
||
} | ||
if (cache.containsKey(key)) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Идея предложила тебе заменить на There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ну так же понятней, нет? Типа тут односложные ифы, и сразу понятно, что происходит, иначе надо думать( There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ну, не знаю, по мне так два однотипных условия в одном выглядят читабельнее. Вообще не суть. |
||
return true; | ||
} | ||
return base.containsKey(key); | ||
} | ||
|
||
/** | ||
* Записывает в хранилище пару ключ-значение. | ||
*/ | ||
@Override | ||
public synchronized void write(K key, V value) { | ||
if (isClosed) { | ||
throw new RuntimeException("Can't write: storage is closed"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. А в There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Поправил There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Нет, не поправил. В There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ааа, пропустил |
||
} else { | ||
cache.put(key, value); | ||
base.put(key, 0L); | ||
|
||
if (cache.size() > MAX_CACHE_SIZE) { | ||
writeCacheToStorage(); | ||
} | ||
} | ||
} | ||
|
||
/** | ||
* Удаляет пару ключ-значение из хранилища. | ||
*/ | ||
@Override | ||
public synchronized void delete(K key) { | ||
if (isClosed) { | ||
throw new RuntimeException("Can't delete: storage is closed"); | ||
} else { | ||
cache.remove(key); | ||
base.remove(key); | ||
} | ||
} | ||
|
||
/** | ||
* Читает все ключи в хранилище. | ||
* <p> | ||
* Итератор должен бросать {@link java.util.ConcurrentModificationException}, | ||
* если данные в хранилище были изменены в процессе итерирования. | ||
*/ | ||
@Override | ||
public Iterator<K> readKeys() { | ||
if (isClosed) { | ||
throw new RuntimeException("Can't iterate: storage is closed"); | ||
} else { | ||
return base.keySet().iterator(); | ||
} | ||
} | ||
|
||
/** | ||
* Возвращает число ключей, которые сейчас в хранилище. | ||
*/ | ||
@Override | ||
public int size() { | ||
if (isClosed) { | ||
throw new RuntimeException("Can't know size: storage is closed"); | ||
} else { | ||
return base.size(); | ||
} | ||
} | ||
|
||
@Override | ||
public synchronized void close() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. При повторном закрытии ничего не нужно делать. У тебя нет этой проверки. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Да, точно |
||
writeCacheToStorage(); | ||
reorganiseStorage(); | ||
downnloadDataToStorage(); | ||
try { | ||
mapStorage.close(); | ||
storage.close(); | ||
} catch (IOException excetion) { | ||
throw new RuntimeException("Can't close storage"); | ||
} | ||
isClosed = true; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. В finally лучше запихнуть. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Сделано! |
||
cache.clear(); | ||
base.clear(); | ||
mutexFile.delete(); | ||
} | ||
|
||
private void uploadDataFromStorage() { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. В моём понимании upload - это когда что-то загружают на крупный ресурс, а download - скачивают с него. И тогда получается, что upload to, download from. А в данном случае ещё и вышеприведённая логика инвертирована. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Ок, хотя мне кажется это немного странным |
||
try { | ||
|
||
int count = -1; | ||
count = mapStorage.readInt(); | ||
|
||
for (int i = 0; i < count; i++) { | ||
K key = keySerializationStrategy.deserializeFromFile(mapStorage); | ||
Long tmp = mapStorage.readLong(); | ||
base.put(key, tmp); | ||
maxOffset = max(maxOffset, tmp); | ||
} | ||
} catch (IOException exception) { | ||
base.clear(); | ||
//throw new RuntimeException("Trouble with storage.db"); | ||
} | ||
} | ||
|
||
private void downnloadDataToStorage() { | ||
try { | ||
mapStorage.close(); | ||
File file = new File(pathname, mapStorageName); | ||
assert (file.delete()); | ||
file = new File(pathname, mapStorageName); | ||
mapStorage = new RandomAccessFile(file, "rw"); | ||
|
||
mapStorage.writeInt(size()); | ||
for (HashMap.Entry<K, Long> entry : base.entrySet()) { | ||
keySerializationStrategy.serializeToFile(entry.getKey(), mapStorage); | ||
mapStorage.writeLong(entry.getValue()); | ||
} | ||
} catch (IOException exception) { | ||
throw new RuntimeException("Trouble with storage.db"); | ||
} | ||
} | ||
|
||
private void writeCacheToStorage() { | ||
if (isClosed) { | ||
throw new RuntimeException("Can't write: storage is closed"); | ||
} else { | ||
try { | ||
for (HashMap.Entry<K, V> entry : cache.entrySet()) { | ||
storage.seek(maxOffset); | ||
valueSerializationStrategy.serializeToFile(entry.getValue(), storage); | ||
long curOffset = storage.getFilePointer(); | ||
base.put(entry.getKey(), maxOffset); | ||
maxOffset = curOffset; | ||
} | ||
cache.clear(); | ||
|
||
} catch (IOException exception) { | ||
throw new RuntimeException("Can't write cache on the disk"); | ||
} | ||
} | ||
} | ||
|
||
private void reorganiseStorage() { | ||
try { | ||
File file = new File(pathname, "newStorage.txt"); | ||
RandomAccessFile newStorage = new RandomAccessFile(file, "rw"); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Через There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. мне же нужно знать offset для каждого элемента, а у DataOutputStream нет такого функционала, или я что-то не понимаю? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Да, стало работать быстрее, спасибо) |
||
|
||
assert (cache.isEmpty()); | ||
|
||
for (HashMap.Entry<K, Long> entry : base.entrySet()) { | ||
storage.seek(entry.getValue()); | ||
Long tmp = newStorage.getFilePointer(); | ||
valueSerializationStrategy.serializeToFile(read(entry.getKey()), newStorage); | ||
base.put(entry.getKey(), tmp); | ||
} | ||
|
||
storage.close(); | ||
File file1 = new File(pathname, storageName); | ||
assert (file1.delete()); | ||
|
||
newStorage.close(); | ||
assert (file.renameTo(file1)); | ||
|
||
} catch (IOException exception) { | ||
throw new RuntimeException("Can't reorganise storage!"); | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
package ru.mipt.java2016.homework.g595.manucharyan.task3; | ||
|
||
import java.io.IOException; | ||
import java.io.RandomAccessFile; | ||
|
||
/** | ||
* @author Vardan Manucharyan | ||
* @since 30.10.16 | ||
*/ | ||
public interface SerializationStrategyRandomAccess<Value> { | ||
|
||
void serializeToFile(Value value, RandomAccessFile output) throws IOException; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Вместо |
||
|
||
Value deserializeFromFile(RandomAccessFile input) throws IOException; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. То же, но про There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Исравил |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package ru.mipt.java2016.homework.g595.manucharyan.task3; | ||
|
||
import java.io.IOException; | ||
import java.io.RandomAccessFile; | ||
|
||
import ru.mipt.java2016.homework.tests.task2.StudentKey; | ||
|
||
/** | ||
* @author Vardan Manucharyan | ||
* @since 30.10.16 | ||
*/ | ||
public class ConcreteStrategyStudentKeyRandomAccess implements SerializationStrategyRandomAccess<StudentKey> { | ||
|
||
@Override | ||
public void serializeToFile(StudentKey value, RandomAccessFile output) throws IOException { | ||
output.writeInt(value.getGroupId()); | ||
ConcreteStrategyStringRandomAccess.writeString(output, value.getName()); | ||
} | ||
|
||
@Override | ||
public StudentKey deserializeFromFile(RandomAccessFile input) throws IOException { | ||
return new StudentKey(input.readInt(), ConcreteStrategyStringRandomAccess.readString(input)); | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Какая клёвая реализация... А точно убрать один уровень вызовов никак нельзя? Лично мне кажется, что я вижу, как можно это сделать.
И кстати, попробуй вернуть назад
writeUTF
, вроде должно побыстрее начать работать :)There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ну, можно inline написать 😃