167 lines
5.2 KiB
C
167 lines
5.2 KiB
C
/*
|
|
Copyright (c) 2011 Joseph Rothrock (rothrock@rothrock.org)
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
in the Software without restriction, including without limitation the rights
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
all copies or substantial portions of the Software.
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
THE SOFTWARE.
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
#include <sys/socket.h>
|
|
#include <netdb.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/select.h>
|
|
#include <fcntl.h>
|
|
#include <unistd.h>
|
|
#include <sys/ipc.h>
|
|
#include <sys/shm.h>
|
|
#include <sys/mman.h>
|
|
#include <sys/stat.h>
|
|
#include <semaphore.h>
|
|
#include <signal.h>
|
|
#include <math.h>
|
|
#include <stdint.h>
|
|
#include <stdbool.h>
|
|
#include <libgen.h>
|
|
#include "longlong.h"
|
|
#include "fnv.h"
|
|
|
|
/*
|
|
Here is the order for setting up a networked connection:
|
|
socket()
|
|
bind()
|
|
listen()
|
|
accept()
|
|
*/
|
|
|
|
// Stuff for .h
|
|
|
|
// Constants -n- Macros
|
|
#define LEFT 0
|
|
#define RIGHT 1
|
|
#define BACKLOG 25
|
|
#define BLOCK_SIZE 4096
|
|
#define MAX_BLOCKS 1073741824
|
|
#define BLOCK_BITMAP_BYTES 134217728
|
|
|
|
// Default starting message size.
|
|
// MSG_SIZE must be larger than RECV_WINDOW
|
|
#define MSG_SIZE 1024
|
|
#define RECV_WINDOW 512
|
|
#define HASH_BITS 16
|
|
#define IDX_ENTRY_SIZE 1024
|
|
#define KEY_LEN (IDX_ENTRY_SIZE - 2*(sizeof(int)) - sizeof(int64_t))
|
|
#define KEYDB_LOCKS 1024
|
|
#define MAX_ARGS 100
|
|
|
|
struct response_struct {
|
|
unsigned int status;
|
|
char* msg;
|
|
};
|
|
|
|
|
|
struct idx { // structure for an index record.
|
|
char key[KEY_LEN];
|
|
int block_offset; // starting block in the db file.
|
|
int length; // db blocks consumed.
|
|
int64_t next; // overflow ptr to next index_record on disk.
|
|
};
|
|
|
|
|
|
struct db_ptr { // a structure that points to a value in the db file.
|
|
int64_t block_offset;
|
|
int blocks;
|
|
};
|
|
|
|
|
|
struct keydb_column {
|
|
char column[KEY_LEN];
|
|
int refcount;
|
|
struct keydb_column *next;
|
|
};
|
|
|
|
|
|
struct keydb_node {
|
|
char column[KEY_LEN];
|
|
int refcount;
|
|
int64_t left;
|
|
int64_t right;
|
|
int64_t next;
|
|
int64_t pos; // file position of this record.
|
|
};
|
|
|
|
|
|
// Globals
|
|
sem_t* BLOCK_BITMAP_LOCK;
|
|
sem_t* HASHBUCKET_LOCK;
|
|
sem_t* KEYDB_LOCK;
|
|
sem_t* IDX_APPEND_LOCK;
|
|
char *SHM_BLOCK_BITMAP;
|
|
char *SHM_HASHBUCKET_BITMAP;
|
|
char *SHM_KEYDB_BITMAP;
|
|
int BLOCK_BITMAP_FD;
|
|
int KEYDB_FD;
|
|
int KEYDB_FREELIST_FD;
|
|
int DB_FD;
|
|
int IDX_FD;
|
|
|
|
|
|
|
|
// Function signatures
|
|
int start_listening(char* host, char* port, int backlog);
|
|
void sigchld_handler(int s);
|
|
void sigterm_handler_parent(int s);
|
|
void sigterm_handler_child(int s);
|
|
int get_hash_val(int bits, char* key);
|
|
int guts(int accept_fd, int listen_fd);
|
|
int extract_command(char *token_vector[], int token_count);
|
|
int tokenize_command(char* msg, char* token_vector[]);
|
|
int write_record(char* key, char* data);
|
|
int write_index(char* key, int block_offset, int length);
|
|
int parse_create(char msg[], int msglen, char** key, char** value);
|
|
int bit_array_set(char bit_array[], int bit);
|
|
int bit_array_test(char bit_array[], int bit);
|
|
int bit_array_clear(char bit_array[], int bit);
|
|
int find(char* key);
|
|
int create_block_reservation(int blocks_needed);
|
|
char* read_record(struct db_ptr db_rec);
|
|
void hash_write_lock(int hash_number);
|
|
void hash_write_unlock(int hash_number);
|
|
void cleanup_and_exit();
|
|
void usage(char *argv);
|
|
struct response_struct create_command(char* token_vector[], int token_count);
|
|
struct response_struct read_command(char* token_vector[], int token_count);
|
|
struct response_struct delete_command(char* token_vector[], int token_count);
|
|
struct response_struct keys_command(char* token_vector[], int token_count);
|
|
int keydb_insert(int fd, char column[], int64_t pos, bool go_next);
|
|
void keydb_lock(int64_t pos);
|
|
void keydb_unlock(int64_t pos);
|
|
int composite_insert(int KEYDB_FD, struct keydb_column *tuple);
|
|
struct keydb_node* keydb_find(int fd, char *key, int64_t pos);
|
|
void* keydb_tree(int fd, int64_t pos, struct keydb_column **list);
|
|
int find_free_key_node(int keydb_fd);
|
|
int connect_and_add_node(int direction, struct keydb_node* buffer, char column[], int pos, int fd);
|
|
int new_subkey_tree(int fd, char column[], int64_t pos, struct keydb_node *buffer);
|
|
int prepare_send_msg(struct response_struct response, char** send_msg);
|