Commit a16f4887 authored by amir.yosef's avatar amir.yosef

Adding LRU Strategy

parent eb57815b
...@@ -9,7 +9,8 @@ public class Main { ...@@ -9,7 +9,8 @@ public class Main {
ServerBuilder builder = new ServerBuilder(); ServerBuilder builder = new ServerBuilder();
director.buildMaster(builder); director.buildMaster(builder);
builder.port(16379); builder.port(16379);
Server server = builder.build(); try (Server server = builder.build()) {
server.start(); server.start();
}
} }
} }
\ No newline at end of file
...@@ -12,7 +12,6 @@ public class CommandFactory implements Factory { ...@@ -12,7 +12,6 @@ public class CommandFactory implements Factory {
} }
public CommandFactory() { public CommandFactory() {
} }
public static CommandFactory getInstance() { public static CommandFactory getInstance() {
......
...@@ -2,6 +2,7 @@ package server; ...@@ -2,6 +2,7 @@ package server;
import client.Client; import client.Client;
import client.primary.MasterClient; import client.primary.MasterClient;
import storage.StorageManager;
import java.io.IOException; import java.io.IOException;
import java.net.ServerSocket; import java.net.ServerSocket;
...@@ -9,12 +10,13 @@ import java.net.Socket; ...@@ -9,12 +10,13 @@ import java.net.Socket;
import java.util.concurrent.ExecutorService; import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors; import java.util.concurrent.Executors;
public class Server { public class Server implements AutoCloseable {
private final int PORT ; private final int PORT;
private final ExecutorService executor; private final ExecutorService executor;
private final String role; private final String role;
StorageManager manager = new StorageManager();
private static Server instance; private static volatile Server instance;
Server(int port, String role) { Server(int port, String role) {
PORT = port; PORT = port;
...@@ -22,9 +24,11 @@ public class Server { ...@@ -22,9 +24,11 @@ public class Server {
this.executor = Executors.newVirtualThreadPerTaskExecutor(); this.executor = Executors.newVirtualThreadPerTaskExecutor();
} }
public static synchronized Server getInstance(int PORT,String role) throws IOException { public static Server getInstance(int PORT, String role) throws IOException {
if (instance == null) { if (role.equalsIgnoreCase("master")) {
instance = new Server(PORT,role); if (instance == null) {
instance = new Server(PORT, role);
}
} }
return instance; return instance;
} }
...@@ -51,4 +55,9 @@ public class Server { ...@@ -51,4 +55,9 @@ public class Server {
task.run(); task.run();
}); });
} }
@Override
public void close() {
manager.shutdown();
}
} }
package storage;
public interface CachePolicy<K, V> {
void add(K key, V value);
V retrieve(K key);
void delete(K key);
void runMaintenance();
}
\ No newline at end of file
package storage;
import java.util.Map;
import java.util.Queue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
public class LRUCachePolicy<K, V> implements CachePolicy<K, V> {
private final int maxCapacity;
private final Map<K, V> cacheMap;
private final Queue<K> accessOrder;
public LRUCachePolicy(int maxCapacity) {
this.maxCapacity = maxCapacity;
this.cacheMap = new ConcurrentHashMap<>(maxCapacity);
this.accessOrder = new ConcurrentLinkedQueue<>();
}
@Override
public void add(K key, V value) {
cacheMap.put(key, value);
updateAccessOrder(key);
}
@Override
public V retrieve(K key) {
V value = cacheMap.get(key);
if (value != null) {
updateAccessOrder(key);
}
return value;
}
@Override
public void delete(K key) {
cacheMap.remove(key);
accessOrder.remove(key);
}
@Override
public void runMaintenance() {
while (cacheMap.size() > maxCapacity) {
evictLeastRecentlyUsed();
}
}
private void updateAccessOrder(K key) {
accessOrder.remove(key);
accessOrder.offer(key);
}
private void evictLeastRecentlyUsed() {
while (!accessOrder.isEmpty()) {
K leastRecentKey = accessOrder.poll();
if (cacheMap.containsKey(leastRecentKey)) {
delete(leastRecentKey);
break;
}
}
}
}
\ No newline at end of file
package storage; package storage;
import java.util.Map; import java.util.Map;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
public class Storage { public class Storage {
private final Map<String, String> storage = new ConcurrentHashMap<>(10000); private final int capacity = 10000;
private final Map<String, Long> timeToExpiration = new ConcurrentHashMap<>(10000); private final CachePolicy<String, String> storage;
private final Map<String, Long> currentTimeForKey = new ConcurrentHashMap<>(10000); private final Map<String, Long> timeToExpiration = new ConcurrentHashMap<>(capacity);
private final Map<String, Long> currentTimeForKey = new ConcurrentHashMap<>(capacity);
private Storage() { private Storage() {
// RdbFileReader reader = new RdbFileReader(); this.storage = new LRUCachePolicy<>(capacity);
//Map<String, String> stringStringMap = reader.readFile();
// storage.putAll(stringStringMap);
//Map<String, Long> keysExpiration = reader.getKeysExpiration();
// timeToExpiration.putAll(keysExpiration);
} }
private static final class StorageHolder { private static final class StorageHolder {
private static final Storage storage = new Storage(); private static final Storage instance = new Storage();
} }
public static Storage getInstance() { public static Storage getInstance() {
return StorageHolder.storage; return StorageHolder.instance;
} }
public void save(String key, String value) { public void save(String key, String value) {
storage.put(key, value); storage.add(key, value);
} }
public void save(String key, String value, Long time) { public void save(String key, String value, Long expirationTime) {
System.out.println("SAVE Storage: " + key);
currentTimeForKey.put(key, System.currentTimeMillis()); currentTimeForKey.put(key, System.currentTimeMillis());
timeToExpiration.put(key, time); timeToExpiration.put(key, expirationTime);
save(key, value); save(key, value);
} }
public String get(String key) { public String get(String key) {
if (isExpired(key)) return ""; if (isExpired(key)) {
return storage.get(key); remove(key);
return "";
}
return storage.retrieve(key);
} }
private boolean isExpired(String key) { private boolean isExpired(String key) {
...@@ -61,5 +57,12 @@ public class Storage { ...@@ -61,5 +57,12 @@ public class Storage {
return false; return false;
} }
private void remove(String key) {
} storage.delete(key);
timeToExpiration.remove(key);
currentTimeForKey.remove(key);
}
void runCachePolicy() {
storage.runMaintenance();
}
}
\ No newline at end of file
package storage;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
public class StorageManager {
private final Storage storage;
private final ScheduledExecutorService scheduler;
public StorageManager() {
this.storage = Storage.getInstance();
this.scheduler = Executors.newSingleThreadScheduledExecutor();
scheduler.scheduleAtFixedRate(this::performMaintenance, 5, 5, TimeUnit.MINUTES);
}
public Storage getStorage() {
return storage;
}
private void performMaintenance() {
storage.runCachePolicy();
System.out.println("Maintenance performed at: " + System.currentTimeMillis());
}
public void shutdown() {
scheduler.shutdown();
try {
if (!scheduler.awaitTermination(60, TimeUnit.SECONDS)) {
scheduler.shutdownNow();
}
} catch (InterruptedException e) {
scheduler.shutdownNow();
}
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment