2010-02-02 23:50:16 +00:00
/*
* network . h
*
* Created on : Feb 2 , 2010
* Author : sears
*/
# ifndef NETWORK_H_
# define NETWORK_H_
# include <stdio.h>
2010-02-10 21:49:50 +00:00
# include <errno.h>
2010-10-02 12:52:41 +00:00
# include <stdint.h>
2010-02-20 01:18:39 +00:00
# include <string>
typedef unsigned char byte ;
# include <cstring>
# include <assert.h>
2010-02-10 21:49:50 +00:00
typedef uint8_t network_op_t ;
2010-02-02 23:50:16 +00:00
2010-02-20 01:18:39 +00:00
typedef uint32_t len_t ;
static const len_t DELETE = ( ( len_t ) 0 ) - 1 ;
2010-09-02 23:03:13 +00:00
# define LOGSTORE_NODELAY
2010-02-20 01:18:39 +00:00
# include <datatuple.h>
2010-02-02 23:50:16 +00:00
//server codes
2010-02-10 21:49:50 +00:00
static const network_op_t LOGSTORE_FIRST_RESPONSE_CODE = 1 ;
static const network_op_t LOGSTORE_RESPONSE_SUCCESS = 1 ;
static const network_op_t LOGSTORE_RESPONSE_FAIL = 2 ;
static const network_op_t LOGSTORE_RESPONSE_SENDING_TUPLES = 3 ;
2010-12-14 21:43:50 +00:00
static const network_op_t LOGSTORE_RESPONSE_RECEIVING_TUPLES = 4 ;
2010-08-30 22:22:25 +00:00
static const network_op_t LOGSTORE_LAST_RESPONSE_CODE = 4 ;
2010-02-02 23:50:16 +00:00
//client codes
2010-02-10 21:49:50 +00:00
static const network_op_t LOGSTORE_FIRST_REQUEST_CODE = 8 ;
static const network_op_t OP_INSERT = 8 ; // Create, Update, Delete
2010-09-16 22:36:48 +00:00
static const network_op_t OP_TEST_AND_SET = 9 ; // Create, Update, Delete iff the datatuple matches the second tuple passed in. (or if it doesn't exist, and isDelete() == true.
static const network_op_t OP_FIND = 10 ; // Read
static const network_op_t OP_SCAN = 11 ;
static const network_op_t OP_BULK_INSERT = 12 ;
static const network_op_t OP_DONE = 13 ; // Please close the connection.
static const network_op_t OP_FLUSH = 14 ;
static const network_op_t OP_SHUTDOWN = 15 ;
static const network_op_t OP_STAT_SPACE_USAGE = 16 ;
static const network_op_t OP_STAT_PERF_REPORT = 17 ;
static const network_op_t OP_STAT_HISTOGRAM = 18 ; // Return N approximately equal size partitions (including split points + cardinalities) N=1 estimates table cardinality.
2010-02-02 23:50:16 +00:00
2010-03-01 21:26:07 +00:00
2010-09-16 22:36:48 +00:00
static const network_op_t OP_DBG_DROP_DATABASE = 19 ;
static const network_op_t OP_DBG_BLOCKMAP = 20 ;
static const network_op_t OP_DBG_NOOP = 21 ;
2011-04-21 00:28:05 +00:00
static const network_op_t OP_DBG_SET_LOG_MODE = 22 ;
static const network_op_t LOGSTORE_LAST_REQUEST_CODE = 22 ;
2010-02-02 23:50:16 +00:00
2010-02-10 21:49:50 +00:00
//error codes
2010-03-01 21:26:07 +00:00
static const network_op_t LOGSTORE_FIRST_ERROR = 27 ;
static const network_op_t LOGSTORE_UNIMPLEMENTED_ERROR = 27 ;
2010-02-10 21:49:50 +00:00
static const network_op_t LOGSTORE_CONN_CLOSED_ERROR = 28 ; // Unexpected EOF
static const network_op_t LOGSTORE_SOCKET_ERROR = 29 ; // The OS returned an error.
static const network_op_t LOGSTORE_REMOTE_ERROR = 30 ; // The other side didn't like our request
static const network_op_t LOGSTORE_PROTOCOL_ERROR = 31 ; // The other side responeded with gibberish.
static const network_op_t LOGSTORE_LAST_ERROR = 31 ;
static const network_op_t OP_INVALID = 32 ;
2010-02-02 23:50:16 +00:00
2010-02-10 21:49:50 +00:00
typedef enum {
LOGSTORE_CLIENT_REQUEST ,
LOGSTORE_SERVER_RESPONSE
} logstore_opcode_type ;
2010-02-02 23:50:16 +00:00
2010-08-11 22:46:55 +00:00
static inline int readfromsocket ( FILE * sockf , void * buf , ssize_t count ) {
2010-08-10 23:56:54 +00:00
ssize_t i = fread_unlocked ( buf , sizeof ( byte ) , count , sockf ) ;
if ( i ! = count ) {
2010-08-30 22:22:25 +00:00
if ( feof_unlocked ( sockf ) ) {
2010-08-10 23:56:54 +00:00
errno = EOF ;
return EOF ;
2010-08-30 22:22:25 +00:00
} else if ( ferror_unlocked ( sockf ) ) {
2010-08-10 23:56:54 +00:00
perror ( " readfromsocket failed " ) ;
errno = - 1 ;
return - 1 ;
}
printf ( " logic bug? unreported short read? \n " ) ;
errno = EOF ;
return EOF ;
}
return 0 ;
}
2010-02-10 21:49:50 +00:00
static inline int readfromsocket ( int sockd , void * buf , ssize_t count )
2010-02-02 23:50:16 +00:00
{
2010-02-10 21:49:50 +00:00
ssize_t n = 0 ;
2010-02-02 23:50:16 +00:00
while ( n < count )
{
2010-02-10 21:49:50 +00:00
ssize_t i = read ( sockd , ( ( byte * ) buf ) + n , count - n ) ;
if ( i = = - 1 ) {
perror ( " readfromsocket failed " ) ;
return errno ;
} else if ( i = = 0 ) {
errno = EOF ;
return errno ;
}
n + = i ;
2010-02-02 23:50:16 +00:00
}
2010-02-10 21:49:50 +00:00
return 0 ;
2010-02-02 23:50:16 +00:00
}
2010-08-11 22:46:55 +00:00
static inline int writetosocket ( FILE * sockf , const void * buf , ssize_t count ) {
2010-08-10 23:56:54 +00:00
ssize_t i = fwrite_unlocked ( ( byte * ) buf , sizeof ( byte ) , count , sockf ) ;
if ( i ! = count ) {
2010-08-30 22:22:25 +00:00
if ( feof_unlocked ( sockf ) ) {
2010-08-10 23:56:54 +00:00
errno = EOF ;
return errno ;
2010-08-30 22:22:25 +00:00
} else if ( ferror_unlocked ( sockf ) ) {
2010-08-10 23:56:54 +00:00
perror ( " writetosocket failed " ) ;
errno = - 1 ;
return - 1 ;
}
printf ( " logic error? unreported short write? \n " ) ;
errno = EOF ;
return EOF ;
}
return 0 ;
}
2010-02-10 21:49:50 +00:00
static inline int writetosocket ( int sockd , const void * buf , ssize_t count )
2010-02-02 23:50:16 +00:00
{
2010-02-10 21:49:50 +00:00
ssize_t n = 0 ;
2010-02-02 23:50:16 +00:00
while ( n < count )
{
2010-02-10 21:49:50 +00:00
ssize_t i = write ( sockd , ( ( byte * ) buf ) + n , count - n ) ;
2010-08-10 23:56:54 +00:00
if ( i = = - 1 ) { // XXX not threadsafe!
2010-02-10 21:49:50 +00:00
perror ( " writetosocket failed " ) ;
return errno ;
} else if ( i = = 0 ) {
errno = EOF ;
return errno ;
}
n + = i ;
2010-02-02 23:50:16 +00:00
}
2010-02-10 21:49:50 +00:00
return 0 ;
}
static inline bool opiserror ( network_op_t op ) {
return ( LOGSTORE_FIRST_ERROR < = op & & op < = LOGSTORE_LAST_ERROR ) ;
}
static inline bool opisrequest ( network_op_t op ) {
return ( LOGSTORE_FIRST_REQUEST_CODE < = op & & op < = LOGSTORE_LAST_REQUEST_CODE ) ;
}
static inline bool opisresponse ( network_op_t op ) {
return ( LOGSTORE_FIRST_RESPONSE_CODE < = op & & op < = LOGSTORE_LAST_RESPONSE_CODE ) ;
}
2010-08-11 22:46:55 +00:00
static inline network_op_t readopfromsocket ( FILE * sockf , logstore_opcode_type type ) {
2010-08-10 23:56:54 +00:00
network_op_t ret ;
2010-08-11 23:27:39 +00:00
fflush_unlocked ( sockf ) ; // our first read after a write is always (?) a readop, so fflush the write here.
ssize_t n = fread_unlocked ( & ret , sizeof ( network_op_t ) , 1 , sockf ) ;
2010-08-10 23:56:54 +00:00
if ( n = = sizeof ( network_op_t ) ) {
// done.
} else if ( n = = 0 ) { // EOF
perror ( " Socket closed mid request. " ) ;
return LOGSTORE_CONN_CLOSED_ERROR ;
} else {
assert ( n = = - 1 ) ; // sizeof(network_op_t) is 1, so short reads are impossible.
perror ( " Could not read opcode from socket " ) ;
return LOGSTORE_SOCKET_ERROR ;
}
// sanity checking
switch ( type ) {
case LOGSTORE_CLIENT_REQUEST : {
if ( ! ( opisrequest ( ret ) | | opiserror ( ret ) ) ) {
fprintf ( stderr , " Read invalid request code %d \n " , ( int ) ret ) ;
if ( opisresponse ( ret ) ) {
2010-08-30 22:22:25 +00:00
fprintf ( stderr , " (also, the request code is a valid response code) \n " ) ;
2010-08-10 23:56:54 +00:00
}
ret = LOGSTORE_PROTOCOL_ERROR ;
}
} break ;
case LOGSTORE_SERVER_RESPONSE : {
if ( ! ( opisresponse ( ret ) | | opiserror ( ret ) ) ) {
fprintf ( stderr , " Read invalid response code %d \n " , ( int ) ret ) ;
if ( opisrequest ( ret ) ) {
2010-08-30 22:22:25 +00:00
fprintf ( stderr , " (also, the response code is a valid request code) \n " ) ;
2010-08-10 23:56:54 +00:00
}
ret = LOGSTORE_PROTOCOL_ERROR ;
}
}
}
return ret ;
}
2010-02-10 21:49:50 +00:00
static inline network_op_t readopfromsocket ( int sockd , logstore_opcode_type type ) {
network_op_t ret ;
ssize_t n = read ( sockd , & ret , sizeof ( network_op_t ) ) ;
if ( n = = sizeof ( network_op_t ) ) {
// done.
} else if ( n = = 0 ) { // EOF
perror ( " Socket closed mid request. " ) ;
return LOGSTORE_CONN_CLOSED_ERROR ;
} else {
assert ( n = = - 1 ) ; // sizeof(network_op_t) is 1, so short reads are impossible.
perror ( " Could not read opcode from socket " ) ;
return LOGSTORE_SOCKET_ERROR ;
}
// sanity checking
switch ( type ) {
case LOGSTORE_CLIENT_REQUEST : {
if ( ! ( opisrequest ( ret ) | | opiserror ( ret ) ) ) {
fprintf ( stderr , " Read invalid request code %d \n " , ( int ) ret ) ;
if ( opisresponse ( ret ) ) {
2010-08-30 22:22:25 +00:00
fprintf ( stderr , " (also, the request code is a valid response code) \n " ) ;
2010-02-10 21:49:50 +00:00
}
ret = LOGSTORE_PROTOCOL_ERROR ;
}
} break ;
case LOGSTORE_SERVER_RESPONSE : {
if ( ! ( opisresponse ( ret ) | | opiserror ( ret ) ) ) {
fprintf ( stderr , " Read invalid response code %d \n " , ( int ) ret ) ;
if ( opisrequest ( ret ) ) {
2010-08-30 22:22:25 +00:00
fprintf ( stderr , " (also, the response code is a valid request code) \n " ) ;
2010-02-10 21:49:50 +00:00
}
ret = LOGSTORE_PROTOCOL_ERROR ;
}
}
}
return ret ;
}
2010-08-11 22:46:55 +00:00
static inline int writeoptosocket ( FILE * sockf , network_op_t op ) {
2010-08-10 23:56:54 +00:00
assert ( opiserror ( op ) | | opisrequest ( op ) | | opisresponse ( op ) ) ;
2010-08-30 22:22:25 +00:00
int ret = writetosocket ( sockf , & op , sizeof ( network_op_t ) ) ;
2010-09-01 17:39:49 +00:00
if ( op = = LOGSTORE_RESPONSE_RECEIVING_TUPLES ) {
fflush_unlocked ( sockf ) ;
}
2010-08-30 22:22:25 +00:00
return ret ;
2010-08-10 23:56:54 +00:00
}
2010-02-10 21:49:50 +00:00
static inline int writeoptosocket ( int sockd , network_op_t op ) {
assert ( opiserror ( op ) | | opisrequest ( op ) | | opisresponse ( op ) ) ;
return writetosocket ( sockd , & op , sizeof ( network_op_t ) ) ;
}
2010-02-19 00:34:41 +00:00
/**
Iterator wire format :
LOGSTORE_RESPONSE_SENDING_TUPLES
TUPLE
TUPLE
TUPLE
datatuple : : DELETE
*/
2010-08-11 22:46:55 +00:00
static inline datatuple * readtuplefromsocket ( FILE * sockf , int * err ) {
2010-08-10 23:56:54 +00:00
len_t keylen , datalen , buflen ;
2010-08-11 22:46:55 +00:00
if ( ( * err = readfromsocket ( sockf , & keylen , sizeof ( keylen ) ) ) ) return NULL ;
2010-08-10 23:56:54 +00:00
if ( keylen = = DELETE ) return NULL ; // *err is zero.
2010-08-11 22:46:55 +00:00
if ( ( * err = readfromsocket ( sockf , & datalen , sizeof ( datalen ) ) ) ) return NULL ;
2010-08-10 23:56:54 +00:00
buflen = datatuple : : length_from_header ( keylen , datalen ) ;
byte * bytes = ( byte * ) malloc ( buflen ) ;
2010-09-01 17:39:49 +00:00
if ( ( * err = readfromsocket ( sockf , bytes , buflen ) ) ) { free ( bytes ) ; return NULL ; }
2010-08-10 23:56:54 +00:00
2011-01-11 22:08:10 +00:00
datatuple * ret = datatuple : : from_bytes ( keylen , datalen , bytes ) ;
free ( bytes ) ;
return ret ;
2010-08-10 23:56:54 +00:00
}
2010-02-19 00:34:41 +00:00
/**
@ param sockd The socket .
@ param error will be set to zero on succes , a logstore error number on failure
@ return a datatuple , or NULL .
*/
static inline datatuple * readtuplefromsocket ( int sockd , int * err ) {
2010-02-10 21:49:50 +00:00
2010-02-20 01:18:39 +00:00
len_t keylen , datalen , buflen ;
2010-02-10 21:49:50 +00:00
2010-02-19 00:34:41 +00:00
if ( ( * err = readfromsocket ( sockd , & keylen , sizeof ( keylen ) ) ) ) return NULL ;
2010-02-20 01:18:39 +00:00
if ( keylen = = DELETE ) return NULL ; // *err is zero.
2010-02-19 00:34:41 +00:00
if ( ( * err = readfromsocket ( sockd , & datalen , sizeof ( datalen ) ) ) ) return NULL ;
2010-02-10 21:49:50 +00:00
buflen = datatuple : : length_from_header ( keylen , datalen ) ;
2011-01-11 22:08:10 +00:00
// TODO remove the malloc / free in readtuplefromsocket, either with a
// two-stage API for datatuple::create, or with realloc.
2010-02-10 21:49:50 +00:00
byte * bytes = ( byte * ) malloc ( buflen ) ;
2010-02-19 00:34:41 +00:00
if ( ( * err = readfromsocket ( sockd , bytes , buflen ) ) ) return NULL ;
2010-02-10 21:49:50 +00:00
2011-01-11 22:08:10 +00:00
datatuple * ret = datatuple : : from_bytes ( keylen , datalen , bytes ) ;
free ( bytes ) ;
return ret ;
2010-02-10 21:49:50 +00:00
}
2010-08-11 22:46:55 +00:00
static inline int writeendofiteratortosocket ( FILE * sockf ) {
return writetosocket ( sockf , & DELETE , sizeof ( DELETE ) ) ;
2010-08-10 23:56:54 +00:00
}
2010-02-20 01:18:39 +00:00
static inline int writeendofiteratortosocket ( int sockd ) {
return writetosocket ( sockd , & DELETE , sizeof ( DELETE ) ) ;
}
2010-08-11 22:46:55 +00:00
static inline int writetupletosocket ( FILE * sockf , const datatuple * tup ) {
2010-08-10 23:56:54 +00:00
len_t keylen , datalen ;
int err ;
if ( tup = = NULL ) {
2010-08-11 22:46:55 +00:00
if ( ( err = writeendofiteratortosocket ( sockf ) ) ) return err ;
2010-08-10 23:56:54 +00:00
} else {
const byte * buf = tup - > get_bytes ( & keylen , & datalen ) ;
2010-08-11 22:46:55 +00:00
if ( ( err = writetosocket ( sockf , & keylen , sizeof ( keylen ) ) ) ) return err ;
if ( ( err = writetosocket ( sockf , & datalen , sizeof ( datalen ) ) ) ) return err ;
if ( ( err = writetosocket ( sockf , buf , datatuple : : length_from_header ( keylen , datalen ) ) ) ) return err ;
2010-08-10 23:56:54 +00:00
}
return 0 ;
}
2010-02-10 21:49:50 +00:00
static inline int writetupletosocket ( int sockd , const datatuple * tup ) {
2010-02-20 01:18:39 +00:00
len_t keylen , datalen ;
2010-02-10 21:49:50 +00:00
int err ;
2010-02-20 01:18:39 +00:00
if ( tup = = NULL ) {
if ( ( err = writeendofiteratortosocket ( sockd ) ) ) return err ;
} else {
const byte * buf = tup - > get_bytes ( & keylen , & datalen ) ;
if ( ( err = writetosocket ( sockd , & keylen , sizeof ( keylen ) ) ) ) return err ;
if ( ( err = writetosocket ( sockd , & datalen , sizeof ( datalen ) ) ) ) return err ;
if ( ( err = writetosocket ( sockd , buf , datatuple : : length_from_header ( keylen , datalen ) ) ) ) return err ;
}
2010-02-10 21:49:50 +00:00
return 0 ;
2010-02-02 23:50:16 +00:00
}
2010-08-11 22:46:55 +00:00
static inline uint64_t readcountfromsocket ( FILE * sockf , int * err ) {
2010-08-10 23:56:54 +00:00
uint64_t ret ;
2010-08-11 22:46:55 +00:00
* err = readfromsocket ( sockf , & ret , sizeof ( ret ) ) ;
2010-08-10 23:56:54 +00:00
return ret ;
}
2010-02-19 00:34:41 +00:00
static inline uint64_t readcountfromsocket ( int sockd , int * err ) {
uint64_t ret ;
* err = readfromsocket ( sockd , & ret , sizeof ( ret ) ) ;
return ret ;
}
2010-08-11 22:46:55 +00:00
static inline int writecounttosocket ( FILE * sockf , uint64_t count ) {
return writetosocket ( sockf , & count , sizeof ( count ) ) ;
2010-08-10 23:56:54 +00:00
}
2010-02-19 00:34:41 +00:00
static inline int writecounttosocket ( int sockd , uint64_t count ) {
return writetosocket ( sockd , & count , sizeof ( count ) ) ;
}
2010-02-02 23:50:16 +00:00
# endif /* NETWORK_H_ */