1 module hunt.database.base.impl.PreparedStatementCache;
2 
3 import hunt.database.base.impl.Connection;
4 
5 import hunt.database.base.impl.command.CloseStatementCommand;
6 import hunt.database.base.impl.command.CommandResponse;
7 import hunt.database.base.impl.PreparedStatement;
8 import hunt.database.base.impl.SocketConnectionBase;
9 
10 import hunt.collection.LinkedHashMap;
11 import hunt.collection.Map;
12 import hunt.Exceptions;
13 
14 import hunt.concurrency.LinkedBlockingQueue;
15 import std.container.dlist;
16 
17 /**
18  * A LRU replacement strategy cache based on {@link java.util.LinkedHashMap} for prepared statements.
19  */
20 class PreparedStatementCache : LinkedHashMap!(string, CachedPreparedStatement) {
21     private int capacity;
22     private DbConnection conn;
23 
24     this(int capacity, DbConnection conn) {
25         super(capacity, 0.75f, true);
26         this.capacity = capacity;
27         this.conn = conn;
28     }
29 
30     override
31     protected bool removeEldestEntry(MapEntry!(string, CachedPreparedStatement) eldest) {
32         bool needRemove = size() > capacity;
33         CachedPreparedStatement cachedPreparedStatementToRemove = eldest.getValue();
34 
35         if (needRemove) {
36             if (cachedPreparedStatementToRemove.resp.succeeded()) {
37                 // close the statement after it has been evicted from the cache
38                 PreparedStatement statement = cachedPreparedStatementToRemove.resp.result();
39                 CloseStatementCommand cmd = new CloseStatementCommand(statement);
40                 cmd.handler = (ar) { };
41                 conn.schedule(cmd);
42             }
43             return true;
44         }
45         return false;
46     }
47 
48     bool isReady() {
49         MapEntry!(string, CachedPreparedStatement) entry = getEldestEntry();
50         if (entry is null) {
51             return true;
52         } else {
53             return entry.getValue().resp !is null;
54         }
55     }
56 
57     int getCapacity() {
58         return this.capacity;
59     }
60 
61     private MapEntry!(string, CachedPreparedStatement) getEldestEntry() {
62         if (size() == 0) {
63             return null;
64         }
65         // return cast(MapEntry!(string, CachedPreparedStatement)) entrySet().toArray()[size() - 1];
66         implementationMissing(false);
67         return null;
68     }
69 }
70 
71 
72 /**
73  * 
74  */
75 class CachedPreparedStatement { // : Handler!(CommandResponse!(PreparedStatement)) 
76     private DList!(ResponseHandler!(PreparedStatement)) waiters;
77     CommandResponse!(PreparedStatement) resp;
78 
79     this() {
80         // FIXME: Needing refactor or cleanup -@zxp at 8/13/2019, 6:27:09 PM
81         // 
82         // waiters = new ArrayDeque!(ResponseHandler!(PreparedStatement))();
83         // waiters = new LinkedBlockingQueue!(ResponseHandler!(PreparedStatement))();
84     }
85 
86     void get(ResponseHandler!(PreparedStatement) handler) {
87         if (resp !is null) {
88             handler(resp);
89         } else {
90             waiters.insertBack(handler);
91         }
92     }
93 
94     // override
95     void handle(CommandResponse!(PreparedStatement) event) {
96         resp = event;
97         ResponseHandler!(PreparedStatement) waiter;
98         while(!waiters.empty()) {
99             waiter = waiters.front();
100             waiter(resp);
101             waiters.removeFront();
102         }
103         // while ((waiter = waiters.poll()) !is null) {
104         //     waiter.handle(resp);
105         // }
106     }
107 }