1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
|
#pragma once
#include "hashtable.h"
#include "shared_memory.h"
#include <csignal>
#include <cstring>
#include <fcntl.h>
#include <optional>
#include <sys/mman.h>
#include <unistd.h>
/**
* @class Server
* @brief Represents the server, which performs operations on the hashtable based on the requests of
* the client.
*/
template <typename K, typename V>
class Server {
public:
/**
* @brief Constructs a new hashtable and initializes a shared memory buffer.
*/
Server()
{
shm_fd = shm_open(SHM_NAME, O_EXCL | O_CREAT | O_RDWR, 0666);
if (-1 == shm_fd) {
std::cout << "Server is already running!" << '\n';
exit(-1);
}
ftruncate(shm_fd, sizeof(SharedMemory));
shared_memory = (SharedMemory*)
mmap(0, sizeof(SharedMemory), PROT_READ | PROT_WRITE, MAP_SHARED, shm_fd, 0);
shared_memory->tail = shared_memory->head = 0;
pthread_mutexattr_t mutex_attr;
pthread_condattr_t cond_attr;
pthread_mutexattr_init(&mutex_attr);
pthread_mutexattr_setpshared(&mutex_attr, PTHREAD_PROCESS_SHARED);
pthread_condattr_init(&cond_attr);
pthread_condattr_setpshared(&cond_attr, PTHREAD_PROCESS_SHARED);
pthread_mutex_init(&shared_memory->mutex, &mutex_attr);
pthread_cond_init(&shared_memory->cond_var, &cond_attr);
}
/**
* @brief Unmaps and unlinks the shared memory.
*/
~Server()
{
munmap(shared_memory, sizeof(SharedMemory));
close(shm_fd);
shm_unlink(SHM_NAME);
}
/**
* @brief Initializes the hashtable.
*
* @param size The number of buckets in the hashtable.
*/
void initialize_hashtable(size_t size) { hash_table = HashTable<K, V>(size); }
/**
* @brief The main loop of the server.
*
* @details The server checks the shared memory for new requests and executes them.
*/
void process_requests()
{
while (true) {
pthread_mutex_lock(&shared_memory->mutex);
if (shared_memory->request[shared_memory->head].status != SENT) {
pthread_cond_wait(&shared_memory->cond_var, &shared_memory->mutex);
}
Request* request = &shared_memory->request[shared_memory->head];
K key = deserialize<K>(request->key);
V value = deserialize<V>(request->value);
switch (request->type) {
case INSERT:
std::cout << "Insert operation" << '\n';
if (hash_table.insert(key, value)) {
strncpy(
request->response,
serialize<std::string>("Inserted successfully").c_str(),
MAX_VALUE_SIZE);
} else {
strncpy(
request->response,
serialize<std::string>("Key is already available").c_str(),
MAX_VALUE_SIZE);
}
break;
case GET: {
std::cout << "Get operation" << '\n';
std::optional<V> result = hash_table.get(key);
if (result.has_value()) {
std::string response = serialize<V>(result.value());
strncpy(request->response, response.c_str(), MAX_VALUE_SIZE);
} else {
strncpy(
request->response,
serialize<std::string>("Couldn't get any value").c_str(),
MAX_VALUE_SIZE);
}
break;
}
case DELETE:
std::cout << "Remove operation" << '\n';
if (hash_table.remove(key)) {
strncpy(
request->response,
serialize<std::string>("Key successfully deleted").c_str(),
MAX_VALUE_SIZE);
} else {
strncpy(
request->response,
serialize<std::string>("Couldn't find the key").c_str(),
MAX_VALUE_SIZE);
}
break;
case PRINT:
std::cout << "Print operation" << '\n';
strncpy(
request->response,
serialize<std::string>(hash_table.string()).c_str(),
MAX_VALUE_SIZE);
break;
default:
break;
}
shared_memory->request[shared_memory->head].status = PROCESSED;
shared_memory->head = (1 + shared_memory->head) % QUEUE_SIZE;
pthread_cond_signal(&shared_memory->cond_var);
pthread_mutex_unlock(&shared_memory->mutex);
}
}
private:
/**
* @brief The hashtable.
*/
HashTable<K, V> hash_table;
/**
* @brief Memory which is shared with the client.
*/
SharedMemory* shared_memory;
/**
* @brief File descriptor for the shared memory, used to unmap and close the memory at the end.
*/
int shm_fd;
};
|