Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in
Toggle navigation
K
key-value-store
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Analytics
Analytics
Repository
Value Stream
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Commits
Open sidebar
Samarth Joshi
key-value-store
Commits
402105da
Commit
402105da
authored
Oct 27, 2020
by
Samarth Joshi
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Removing commented code
parent
2a0b2d19
Changes
4
Show whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
22 additions
and
193 deletions
+22
-193
KVClient
KVClient
+0
-0
KVClient.c
KVClient.c
+7
-18
KVServer
KVServer
+0
-0
KVServer.c
KVServer.c
+15
-175
No files found.
KVClient
View file @
402105da
No preview for this file type
KVClient.c
View file @
402105da
...
...
@@ -14,21 +14,7 @@ client library interfaces to do the actual operations.
#define SA struct sockaddr
#include "KVClientLibrary.c"
struct
message
*
requestMessage
;
void
func
(
int
sockfd
,
struct
message
*
requestMessage
)
{
char
buff
[
MAX
];
int
n
=
0
;
for
(;;)
{
bzero
(
buff
,
sizeof
(
buff
));
if
(
1
)
{
n
++
;
printf
(
"[Message sent to server]
\n
[[Status:%c]
\n
[Key:%s]
\n
[Value:%s]]
\n
"
,
requestMessage
->
status
,
requestMessage
->
key
,
requestMessage
->
value
);
write
(
sockfd
,
requestMessage
,
sizeof
(
struct
message
));
sleep
(
2
);
}
}
}
int
main
(
int
argc
,
char
const
*
argv
[])
{
int
sock
=
0
,
valread
;
...
...
@@ -59,9 +45,12 @@ int main(int argc, char const *argv[])
char
key
[
256
]
=
"abc"
;
char
value
[
256
]
=
"cde"
;
char
error
[
256
];
printf
(
"%d"
,(
int
)
put
(
sock
,
key
,
value
,
error
));
printf
(
"%d"
,(
int
)
del
(
sock
,
key
,
error
));
printf
(
"%d"
,(
int
)
get
(
sock
,
key
,
value
,
error
));
//printf("%d",(int)put(sock,key, value,error));
//printf("%d",(int)del(sock,key,error));
//printf("%d",(int)get(sock,key, value,error));
while
(
1
)
{
printf
(
"%d"
,(
int
)
put
(
sock
,
key
,
value
,
error
));
}
return
0
;
}
\ No newline at end of file
KVServer
View file @
402105da
No preview for this file type
KVServer.c
View file @
402105da
/*
KVServer will consist of a main thread that will perform the following steps:
1. It will read a config file and set up a listening socket on a port specified in the config file.
2. Create n threads at startup which will be specified in the config file.
3. Perform accept() on the listening socket and pass each established connection to one of
the n threads in a round robin fashion. For example, the first connection is passed on to
the first thread of those n thread for processing, and so on.
The KVServer will also have worker threads that are responsible for the following actions:
1. Each worker thread will set up and monitor an epoll context for the set of connections it
is responsible for.
2. It runs an infinite loop that will monitor its client connections for work (in addition, if there
are new connections for the thread, it must add it to the epoll context). After reading
requests from clients, it will process those requests, and write a response back to the
client.
Key Value Cache: The server will have limited memory (specified via a config file parameter
that lays out how many key value entries the server is allowed to hold in memory) and so this
will serve as cache to the files that will hold the persistent representation of the data. The cache
will be a fully associative cache (flat structure) with two possible replacement/eviction policies:
a. LRU:
b. LFU: Least Frequently used
Dirty entries evicted from this cache will have to be written out to the persistent representation
which will be a file. You are free to use locality to evict more than one entry and bring in
additional entries by locality to drive performance.
Persistence: All keys and corresponding values are stored on disk in files. How you organize
the keys into files is up to you. We suggest that you keep keys that are “close” to each other in a
single file. You also need to think about how keys are arranged in a file - if you want to read in
one key (and corresponding value), you should do a lseek to the specific place in the file
where the key will be. The meta data about key positions and files that exist can be in memory -
think about using bitmaps.
Interfaces:
● Your key-value server will support 3 interfaces:
1. Value GET (Key k): Retrieves the key-value pair corresponding to the provided key.
2. PUT (Key k, Value v): Inserts/Overwrites the key-value pair into the store.
3. DEL( Key k): Removes the key-value pair corresponding to the provided key from the
store.
● You must use the exact request/response formats defined later in the specification for
communication between external and internal components.
● 'Keys' and 'values' are always strings with non-zero lengths. They cannot be nulls either.
● Each key and value cannot be greater than 256 bytes . If the size is breached, return an
error. (Assume each character to be 1 byte in size)
● When PUTing a key-value pair, if the key already exists, then the value is overwritten.
● When GETing a value, if the key does not exist, return an error message.
● You should ensure the following synchronization properties in your key-value service:
1. Reads (GETs) and updates (PUTs and DELETEs) are atomic.
2. An update consists of modifying a (key, value) entry in both the cache and
persistent representation (you can choose to do this lazily).
3. Do NOT lock the entire cache for each write. Only lock that entry so that
operations on other keys can proceed in parallel. If you do use locks, use multiple
readers single writer locks for efficiency.
KVClient
*/
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
...
...
@@ -82,6 +20,8 @@ void *worker(void *args) {
int
epollfd
;
int
*
newfd
=
malloc
(
sizeof
(
int
));
char
*
name
=
(
char
*
)
malloc
(
5
*
sizeof
(
char
));
epollfd
=
epoll_create1
(
0
);
if
(
epollfd
==
-
1
)
{
perror
(
"epoll_create1"
);
...
...
@@ -105,13 +45,9 @@ void *worker(void *args) {
}
for
(
i
=
0
;
i
<
nfds
;
++
i
)
{
if
(
events
[
i
].
data
.
fd
==
read_pipe
)
{
/* if we get a request from main thread to add new client
ie. events[i].data.fd is equal to the pipe which we use to talk with main thread
- read this newfd from pipe
- add this newfd to epoll instance to monitor for client requests
*/
/* if we get a request from main thread to add new client */
read
(
read_pipe
,
newfd
,
sizeof
(
newfd
));
printf
(
"
\n
read %d
\n
"
,
*
newfd
);
printf
(
"
[%s] read %d
\n
"
,
name
,
*
newfd
);
ev
.
data
.
fd
=*
newfd
;
ev
.
events
=
EPOLLIN
|
EPOLLRDHUP
;
if
(
epoll_ctl
(
epollfd
,
EPOLL_CTL_ADD
,
*
newfd
,
&
ev
)
==
-
1
)
{
...
...
@@ -119,18 +55,13 @@ void *worker(void *args) {
exit
(
EXIT_FAILURE
);
}
}
else
{
/* if we get a request from client
ie. events[i].data.fd is equal to the client socket fd
*/
/* if we get a request from client (GET, PUSH, DEL) */
int
flag
=
events
[
i
].
events
;
if
(
flag
&
EPOLLRDHUP
)
{
/* Connection was closed.
- Remove socket from epoll instance
- Close the socket and dont process more info from this socket
Note: This if block should be before EPOLLIN
*/
/* Connection was closed. */
epoll_ctl
(
epollfd
,
EPOLL_CTL_DEL
,
events
[
i
].
data
.
fd
,
NULL
);
close
(
events
[
i
].
data
.
fd
);
continue
;
...
...
@@ -158,21 +89,19 @@ void *worker(void *args) {
int
main
(
int
argc
,
int
argv
)
{
int
i
;
int
next
=
0
;
// to decide which worker thread to assign client in round robin fashion
pthread_t
*
threads
;
// set of all worker threads
int
pool_thread_size
=
1
;
// TODO: get pool thread size from config file
int
next
_thread_to_assign
=
0
;
pthread_t
*
worker_threads
;
int
pool_thread_size
=
5
;
// TODO: get pool thread size from config file
int
sockfd
,
newsockfd
,
portno
,
clilen
,
n
;
struct
sockaddr_in
serv_addr
,
cli_addr
;
//int *pipes = (int*) malloc(pool_thread_size * 2 * sizeof(pipes));
int
pipes
[
5
][
2
];
// TODO: initialize pipes dynamically
// initialize thread pool with initial pool size
threads
=
malloc
(
pool_thread_size
*
sizeof
(
pthread_t
));
worker_threads
=
malloc
(
pool_thread_size
*
sizeof
(
pthread_t
));
for
(
i
=
0
;
i
<
pool_thread_size
;
i
++
)
{
pipe
(
pipes
[
i
]);
pthread_create
(
&
threads
[
i
],
NULL
,
worker
,
&
pipes
[
i
]);
pthread_create
(
&
worker_
threads
[
i
],
NULL
,
worker
,
&
pipes
[
i
]);
}
sockfd
=
socket
(
AF_INET
,
SOCK_STREAM
,
0
);
...
...
@@ -202,101 +131,12 @@ int main (int argc, int argv) {
if
(
newsockfd
<
0
)
perror
(
"ERROR on accept"
);
write
(
pipes
[
next
][
1
],
&
newsockfd
,
sizeof
(
newsockfd
));
write
(
pipes
[
next
_thread_to_assign
][
1
],
&
newsockfd
,
sizeof
(
newsockfd
));
printf
(
"main thread value: %d
\n
"
,
newsockfd
);
fflush
(
stdout
);
next
=
(
next
+
1
)
%
pool_thread_size
;
next
_thread_to_assign
=
(
next_thread_to_assign
+
1
)
%
pool_thread_size
;
}
return
0
;
}
\ No newline at end of file
/*
#include <stdio.h>
#include <netdb.h>
#include <netinet/in.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/socket.h>
#include <sys/types.h>
#include "KVMessageFormat.h"
#define MAX 80
#define PORT 6969
#define SA struct sockaddr
// Function designed for chat between client and server.
void func(int sockfd)
{
printf("receive functions:");
char buff[ sizeof(struct message)];
int n;
struct message* requestMessage=malloc(sizeof(struct message));
// infinite loop for chat
// read the message from client and copy it in buffer
read( sockfd , buff, sizeof(struct message));
// print buffer which contains the client contents
printf("From client: %c\t To client : ", buff[0]);
}
// Driver function
int main(int argc, char const *argv[])
{
int server_fd, new_socket, valread;
struct sockaddr_in address;
int opt = 1;
int addrlen = sizeof(address);
char buffer[1024] = {0};
char *hello = "Hello from server";
// Creating socket file descriptor
if ((server_fd = socket(AF_INET, SOCK_STREAM, 0)) == 0)
{
perror("socket failed");
exit(EXIT_FAILURE);
}
// Forcefully attaching socket to the port 8080
if (setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR | SO_REUSEPORT,
&opt, sizeof(opt)))
{
perror("setsockopt");
exit(EXIT_FAILURE);
}
address.sin_family = AF_INET;
address.sin_addr.s_addr = INADDR_ANY;
address.sin_port = htons( PORT );
// Forcefully attaching socket to the port 8080
if (bind(server_fd, (struct sockaddr *)&address,
sizeof(address))<0)
{
perror("bind failed");
exit(EXIT_FAILURE);
}
if (listen(server_fd, 3) < 0)
{
perror("listen");
exit(EXIT_FAILURE);
}
if ((new_socket = accept(server_fd, (struct sockaddr *)&address,
(socklen_t*)&addrlen))<0)
{
perror("accept");
exit(EXIT_FAILURE);
}
struct message *requestMessage= malloc(sizeof(struct message));
valread = read( new_socket , requestMessage, sizeof(struct message));
printf("[Message Received from client]\n[[Status:%c]\n[Key:%s]\n[Value:%s]]",requestMessage->status,requestMessage->key,requestMessage->value);
struct message *replyMessage=malloc(sizeof(struct message));
replyMessage->status='0';
char buff[256]="success";
memcpy(replyMessage->key,buff,256);
replyMessage->value[0]='\0';
send(new_socket , replyMessage , sizeof(struct message) , 0 );
printf("\n[Message sent to client]\n[[Status:%c]\n[Key:%s]\n[Value:%s]]",replyMessage->status,replyMessage->key,replyMessage->value);
return 0;
}
*/
\ No newline at end of file
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment