Skip to content

Commit 5ae6c94

Browse files
committed
initial implementation of lru, don't know if it works
1 parent 720355c commit 5ae6c94

12 files changed

+297
-33
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -59,5 +59,5 @@ clean:
5959
rm -rf $(BUILD_TARGET)/
6060
rm -rf test/coverage.info test/out/ test_app.c.gcov
6161
rm test/mock_malloc.gcda test/mock_malloc.gcno test/test_app.gcda test/test_app.gcno unity/unity.gcda unity/unity.gcno
62-
rm -rf main.c.gcov server.c.gcov src/connection.gcda src/connection.gcno src/coverage.info src/hashtable.gcda src/hashtable.gcno src/main.gcda src/main.gcno src/out/ src/server.gcda src/server.gcno src/signal_handler.gcda src/signal_handler.gcno src/logger.gcno src/logger.gcda src/ttl_manager.gcno src/ttl_manager.gcda test/test_ttl_cache.gcno test/test_ttl_cache.gcda test/test_lru_cache.gcno test/test_lru_cache.gcda test/util.gcno test/util.gcda
62+
rm -rf main.c.gcov server.c.gcov src/connection.gcda src/connection.gcno src/coverage.info src/hashtable.gcda src/hashtable.gcno src/main.gcda src/main.gcno src/out/ src/server.gcda src/server.gcno src/signal_handler.gcda src/signal_handler.gcno src/logger.gcno src/logger.gcda src/ttl_manager.gcno src/ttl_manager.gcda test/test_ttl_cache.gcno test/test_ttl_cache.gcda test/test_lru_cache.gcno test/test_lru_cache.gcda test/util.gcno test/util.gcda src/lru_manager.gcno src/lru_manager.gcda
6363

include/common.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,6 @@ typedef struct {
3232
} node_data_t;
3333

3434

35-
extern hash_table_t *hash_table_main;
35+
//extern hash_table_t *hash_table_main;
3636

3737
#endif // COMMON_H

include/config.h

+5
Original file line numberDiff line numberDiff line change
@@ -87,6 +87,11 @@
8787
*/
8888
#define HASH_TABLE_STARTING_SIZE 1000
8989

90+
/*
91+
* The maximum capacity an LRU can store
92+
* */
93+
#define LRU_CAPACITY 10000
94+
9095
// ======================= Testing Configuration =======================
9196
#ifdef TESTING
9297
/**

include/connection.h

+3-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
#include "../include/ttl_manager.h"
1313
#include <stdbool.h>
1414
#include <stdatomic.h>
15-
#include "../include/ttl_manager.h"
15+
#include "../include/lru_manager.h"
1616
#include "../include/response.h"
1717

1818

@@ -37,8 +37,8 @@ void remove_client_from_list(node_data_t *client_data);
3737
void handle_client_read(client_t *client, struct epoll_event *ev, int epoll_fd);
3838
void handle_client_write(client_t *client, struct epoll_event *ev, int epoll_fd);
3939
void delete_resources(int epoll_fd, client_t *client, struct epoll_event *ev);
40-
void custom_cleanup(void *arg);
41-
bool is_entry_expired(ttl_entry_t *entry, time_t current_time);
40+
//void custom_cleanup(void *arg);
41+
//bool is_entry_expired(ttl_entry_t *entry, time_t current_time);
4242

4343

4444
void increment_active_connections(void);

include/lru_manager.h

+27-2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,29 @@
1-
#ifndef TTL_MANAGER_H
2-
#define TTL_MANAGER_H
1+
#ifndef LRU_MANAGER_H
2+
#define LRU_MANAGER_H
3+
4+
#include "hashtable.h"
5+
6+
typedef struct lru_entry {
7+
char* key;
8+
void *value;
9+
struct lru_entry *previous;
10+
struct lru_entry *next;
11+
12+
} lru_entry_t;
13+
14+
typedef struct lru_manager {
15+
hash_table_t *hash_table_main;
16+
long size;
17+
long capacity;
18+
lru_entry_t *head;
19+
lru_entry_t *tail;
20+
21+
} lru_manager_t;
22+
23+
24+
void custom_cleanup_lru(void *arg);
25+
void lru_set(char *key, char *value, char *response);
26+
27+
extern lru_manager_t* lru_manager;
328

429
#endif

include/ttl_manager.h

+5
Original file line numberDiff line numberDiff line change
@@ -29,5 +29,10 @@ typedef struct ttl_manager {
2929
void ttl_set(char *key, char *value, char *ttl_value, char *response);
3030
void ttl_get(char *key, char *response);
3131
void ttl_delete(char *key, char *response);
32+
void custom_cleanup_ttl(void *arg);
33+
bool is_entry_expired(ttl_entry_t *entry, time_t current_time);
34+
35+
// Vars
36+
extern ttl_manager_t* ttl_manager;
3237

3338
#endif // TTL_MANAGER_H

src/connection.c

+6-3
Original file line numberDiff line numberDiff line change
@@ -16,9 +16,12 @@ static void connections_cmd(char *response) {
1616
write_response_int(response, get_active_connections());
1717
}
1818

19-
static void keys_num_cmd(char *response) {
20-
write_response_int(response, hash_table_main->size);
19+
static void keys_num_ttl_cmd(char *response) {
20+
write_response_int(response, ttl_manager->hash_table_main->size);
2121
}
22+
// static void keys_num_lru_cmd(char *response) {
23+
// write_response_int(response, lru_manager->hash_table_main->size);
24+
// }
2225
// Remove client from the linked list
2326
void remove_client_from_list(node_data_t *client_data) {
2427
if (client_data && client_data->data.client) {
@@ -90,7 +93,7 @@ static void process_command_for_ttl(char *command, char *response) {
9093
connections_cmd(response);
9194

9295
} else if (strncmp(command_type, "KEYS_NUM", 8) == 0 && num_args == 1) {
93-
keys_num_cmd(response);
96+
keys_num_ttl_cmd(response);
9497

9598
} else {
9699
// Unknown command

src/hashtable.c

+3-1
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
#include <pthread.h>
1+
// #include <pthread.h>
22
#include <string.h>
33
#ifdef TESTING
44
// #warning "TESTING macro is defined"
@@ -120,6 +120,8 @@ int hash_table_set(hash_table_t *ht, char *key, void *value, size_t size,
120120
ht->size++;
121121
// printf("---increase size: %d\n", ht->size);
122122

123+
// consider returning the value, in our case it will be lru_entry_t*
124+
// return entry->value;
123125
return 0;
124126
}
125127

src/lru_manager.c

+184-7
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,187 @@
1+
#include "../include/lru_manager.h"
12

2-
typedef struct lru_entry {
3-
void *value;
4-
struct lru_entry *previous;
5-
struct lru_entry *next;
3+
// #include "../include/config.h"
4+
#include "../include/logger.h"
5+
#include "../include/response.h"
66

7-
} lru_entry_t;
7+
void custom_cleanup_lru(void *arg) {
8+
lru_entry_t *lru_entry = arg;
9+
if (lru_entry && lru_entry->value && lru_entry->key) {
10+
free(lru_entry->value);
11+
free(lru_entry->key);
12+
}
13+
}
814

9-
typedef struct lru_manager {
10-
} lru_manager_t;
15+
void add_entry_to_front_of_q(lru_entry_t *entry) {
16+
if (lru_manager->head == NULL) {
17+
lru_manager->head = entry;
18+
lru_manager->tail = entry;
19+
return;
20+
}
21+
entry->next = lru_manager->head;
22+
lru_manager->head->previous = entry;
23+
lru_manager->head = entry;
24+
}
25+
26+
// It removes all the references from the Q but doesn't delete/free the entry
27+
void remove_entry_from_q(lru_entry_t *entry) {
28+
if (entry->previous != NULL) {
29+
entry->previous->next = entry->next;
30+
} else {
31+
// If it doesn't have previous then it is the head
32+
lru_manager->head = entry->next;
33+
}
34+
35+
if (entry->next != NULL) {
36+
entry->next->previous = entry->previous;
37+
} else {
38+
// It means it is the tail
39+
lru_manager->tail = entry->previous;
40+
}
41+
42+
entry->previous = NULL;
43+
entry->next = NULL;
44+
}
45+
46+
// It removes and deletes the entry completely from the Q
47+
// void delete_entry_from_q(lru_entry_t *entry) {
48+
// remove_entry_from_q(entry);
49+
// free(entry);
50+
// }
51+
52+
void move_entry_to_front_of_q(lru_entry_t *entry) {
53+
if (lru_manager->head == entry) {
54+
return;
55+
}
56+
// doesn't free the entry, only removes the refernces
57+
remove_entry_from_q(entry);
58+
add_entry_to_front_of_q(entry);
59+
}
60+
61+
// lru_set
62+
void lru_set(char *key, char *value, char *response) {
63+
char *response_value = NULL;
64+
log_debug("key: %s\n", key);
65+
log_debug("value: %s\n", value);
66+
67+
lru_entry_t *lru_entry = hash_table_get(lru_manager->hash_table_main, key);
68+
if (lru_entry != NULL) {
69+
// move to front of list
70+
move_entry_to_front_of_q(lru_entry);
71+
72+
// change the value
73+
void *new_value_ptr = strdup(value);
74+
if (!new_value_ptr) {
75+
fprintf(stderr,
76+
"failed to allocate memory for new value during lru_set");
77+
response_value = "ERROR: MEMORY ALLOC FAILURE";
78+
write_response_str(response, response_value);
79+
return;
80+
}
81+
// free the old value
82+
free(lru_entry->value);
83+
// set the new value to the entry
84+
lru_entry->value = new_value_ptr;
85+
86+
// send response
87+
response_value = "OK";
88+
write_response_str(response, response_value);
89+
return;
90+
}
91+
92+
// key doesn't exist, so create a new and store it
93+
94+
lru_entry_t new_lru_entry;
95+
new_lru_entry.value = strdup(value);
96+
if (!new_lru_entry.value) {
97+
fprintf(stderr,
98+
"failed to allocate memory during setting new entry value in "
99+
"lru_set");
100+
response_value = "ERROR: MEMORY ALLOC FAILURE";
101+
write_response_str(response, response_value);
102+
return;
103+
}
104+
new_lru_entry.key = strdup(key);
105+
if (!new_lru_entry.key) {
106+
free(new_lru_entry.value);
107+
fprintf(stderr,
108+
"failed to allocate memory during setting new entry key in "
109+
"lru_set");
110+
response_value = "ERROR: MEMORY ALLOC FAILURE";
111+
write_response_str(response, response_value);
112+
return;
113+
}
114+
new_lru_entry.next = NULL;
115+
new_lru_entry.previous = NULL;
116+
117+
// check if it fits in the current capacity and if not remove the last entry
118+
// from the Q
119+
if (lru_manager->size >= lru_manager->capacity) {
120+
// remove it from the Q
121+
remove_entry_from_q(lru_manager->tail);
122+
// remove the last entry from hashtable
123+
hash_table_remove(lru_manager->hash_table_main, lru_manager->tail->key,
124+
custom_cleanup_lru);
125+
lru_manager->size--;
126+
}
127+
128+
int error =
129+
hash_table_set(lru_manager->hash_table_main, key, &new_lru_entry,
130+
sizeof(new_lru_entry), custom_cleanup_lru);
131+
if (error != 0) {
132+
fprintf(stderr, "failed to allocate memory during lru set_value");
133+
response_value = "ERROR: MEMORY ALLOC FAILURE";
134+
write_response_str(response, response_value);
135+
return;
136+
}
137+
138+
// This is neccesary because the hashtable recreates it's own entries and we
139+
// want the actual created entry. Can be optimized by modifing the hashtable
140+
// to return the value when we set a new entry
141+
lru_entry_t *lru_entry_new =
142+
hash_table_get(lru_manager->hash_table_main, key);
143+
if (lru_entry_new == NULL) {
144+
fprintf(stderr, "failed, something went terribly wrong! ");
145+
response_value = "ERROR: UNEXPECTED FAILURE ON RETRIEVING THE KEY";
146+
write_response_str(response, response_value);
147+
return;
148+
}
149+
150+
add_entry_to_front_of_q(lru_entry_new);
151+
lru_manager->size++;
152+
153+
response_value = "OK";
154+
write_response_str(response, response_value);
155+
}
156+
157+
// lru_get
158+
void lru_get(char *key, char *response) {
159+
char *response_value = NULL;
160+
lru_entry_t *lru_entry = hash_table_get(lru_manager->hash_table_main, key);
161+
162+
if (lru_entry == NULL) {
163+
response_value = "ERROR: KEY NOT FOUND";
164+
write_response_str(response, response_value);
165+
return;
166+
}
167+
168+
response_value = lru_entry->value;
169+
move_entry_to_front_of_q(lru_entry);
170+
write_response_str(response, response_value);
171+
}
172+
173+
// lru_delete
174+
void lru_delete(char *key, char *response) {
175+
char *response_value = NULL;
176+
lru_entry_t *lru_entry = hash_table_get(lru_manager->hash_table_main, key);
177+
if (lru_entry == NULL) {
178+
response_value = "ERROR: KEY NOT FOUND";
179+
write_response_str(response, response_value);
180+
return;
181+
}
182+
remove_entry_from_q(lru_entry);
183+
hash_table_remove(lru_manager->hash_table_main, key, custom_cleanup_lru);
184+
lru_manager->size--;
185+
response_value = "OK";
186+
write_response_str(response, response_value);
187+
}

src/lru_manager.gcno

-48 Bytes
Binary file not shown.

0 commit comments

Comments
 (0)