/** Create S3HttpClient object. method: HTTP method: GET, PUT, etc url: string which contains S3 server's URL Returns: new S3HttpClient object or NULL if failed */ gpointer s3http_client_create (Application *app) { S3HttpClient *http; http = g_new0 (S3HttpClient, 1); http->app = app; http->evbase = application_get_evbase (app); http->dns_base = application_get_dnsbase (app); http->is_acquired = FALSE; // default state http->connection_state = S3C_disconnected; http->output_buffer = evbuffer_new (); http->input_buffer = evbuffer_new (); http->bev = NULL; http->http_uri = NULL; http->l_input_headers = NULL; http->l_output_headers = NULL; s3http_client_request_reset (http); return (gpointer) http; }
// create S3HttpConnection object // establish HTTP connections to S3 gpointer s3http_connection_create (Application *app) { S3HttpConnection *con; int port; AppConf *conf; con = g_new0 (S3HttpConnection, 1); if (!con) { LOG_err (CON_LOG, "Failed to create S3HttpConnection !"); return NULL; } conf = application_get_conf (app); con->app = app; con->bucket_name = g_strdup (application_get_bucket_name (app)); con->is_acquired = FALSE; port = application_get_port (app); // if no port is specified, libevent returns -1 if (port == -1) { port = conf->http_port; } LOG_debug (CON_LOG, "Connecting to %s:%d", application_get_host (app), port ); // XXX: implement SSL con->evcon = evhttp_connection_base_new ( application_get_evbase (app), application_get_dnsbase (app), application_get_host (app), port ); if (!con->evcon) { LOG_err (CON_LOG, "Failed to create evhttp_connection !"); return NULL; } evhttp_connection_set_timeout (con->evcon, conf->timeout); evhttp_connection_set_retries (con->evcon, conf->retries); evhttp_connection_set_closecb (con->evcon, s3http_connection_on_close, con); return (gpointer)con; }
// retrieve file buffer from local storage // if success == TRUE then "buf" contains "size" bytes of data void cache_mng_retrieve_file_buf (CacheMng *cmng, fuse_ino_t ino, size_t size, off_t off, cache_mng_on_retrieve_file_buf_cb on_retrieve_file_buf_cb, void *ctx) { struct _CacheContext *context; struct _CacheEntry *entry; context = cache_context_create (size, ctx); context->cb.retrieve_cb = on_retrieve_file_buf_cb; entry = g_hash_table_lookup (cmng->h_entries, GUINT_TO_POINTER (ino)); if (entry && range_contain (entry->avail_range, off, off + size)) { int fd; ssize_t res; char path[PATH_MAX]; if (ino != entry->ino) { LOG_err (CMNG_LOG, "Requested inode doesn't match hashed key!"); if (context->cb.retrieve_cb) context->cb.retrieve_cb (NULL, 0, FALSE, context->user_ctx); cache_context_destroy (context); return; } cache_mng_file_name (cmng, path, sizeof (path), ino); fd = open (path, O_RDONLY); context->buf = g_malloc (size); res = pread (fd, context->buf, size, off); close (fd); context->success = (res == (ssize_t) size); if (!context->success) { g_free (context->buf); context->buf = NULL; } // move entry to the front of q_lru g_queue_unlink (cmng->q_lru, entry->ll_lru); g_queue_push_head_link (cmng->q_lru, entry->ll_lru); } else { LOG_debug (CMNG_LOG, "Entry isn't found or doesn't contain requested range: %"INO_FMT, INO ino); } context->ev = event_new (application_get_evbase (cmng->app), -1, 0, cache_read_cb, context); // fire this event at once event_active (context->ev, 0, 0); event_add (context->ev, NULL); }
StatSrv *stat_srv_create (Application *app) { StatSrv *stat_srv; stat_srv = g_new0 (StatSrv, 1); stat_srv->app = app; stat_srv->q_op_history = g_queue_new (); stat_srv->boot_time = time (NULL); // stats server is disabled if (!conf_get_boolean (application_get_conf (stat_srv->app), "statistics.enabled")) { return stat_srv; } stat_srv->http = evhttp_new (application_get_evbase (app)); if (!stat_srv->http) { LOG_err (STAT_LOG, "Failed to create statistics server !"); return NULL; } // bind if (evhttp_bind_socket (stat_srv->http, conf_get_string (application_get_conf (stat_srv->app), "statistics.host"), conf_get_int (application_get_conf (stat_srv->app), "statistics.port")) == -1) { LOG_err (STAT_LOG, "Failed to bind statistics server to %s:%d", conf_get_string (application_get_conf (stat_srv->app), "statistics.host"), conf_get_int (application_get_conf (stat_srv->app), "statistics.port") ); return NULL; } // install handlers evhttp_set_cb (stat_srv->http, conf_get_string (application_get_conf (stat_srv->app), "statistics.stats_path"), stat_srv_on_stats_cb, stat_srv); evhttp_set_gencb (stat_srv->http, stat_srv_on_gen_cb, stat_srv); return stat_srv; }
// creates connection pool object // create client_count clients // return NULL if error S3ClientPool *s3client_pool_create (Application *app, gint client_count, S3ClientPool_client_create client_create, S3ClientPool_client_destroy client_destroy, S3ClientPool_client_set_on_released_cb client_set_on_released_cb, S3ClientPool_client_check_rediness client_check_rediness) { S3ClientPool *pool; gint i; PoolClient *pc; AppConf *conf; conf = application_get_conf (app); pool = g_new0 (S3ClientPool, 1); pool->app = app; pool->evbase = application_get_evbase (app); pool->dns_base = application_get_dnsbase (app); pool->l_clients = NULL; pool->q_requests = g_queue_new (); pool->max_requests = conf->max_requests_per_pool; for (i = 0; i < client_count; i++) { pc = g_new0 (PoolClient, 1); pc->pool = pool; pc->client = client_create (app); pc->client_check_rediness = client_check_rediness; pc->client_destroy = client_destroy; // add to the list pool->l_clients = g_list_append (pool->l_clients, pc); // add callback client_set_on_released_cb (pc->client, s3client_pool_on_client_released, pc); } return pool; }
// store file buffer into local storage // if success == TRUE then "buf" successfuly stored on disc void cache_mng_store_file_buf (CacheMng *cmng, fuse_ino_t ino, size_t size, off_t off, unsigned char *buf, cache_mng_on_store_file_buf_cb on_store_file_buf_cb, void *ctx) { struct _CacheContext *context; struct _CacheEntry *entry; ssize_t res; int fd; char path[PATH_MAX]; guint64 old_length, new_length; guint64 range_size; time_t now; range_size = (guint64)(off + size); // limit the number of cache checks now = time (NULL); if (cmng->check_time < now && now - cmng->check_time >= 10) { // remove data until we have at least size bytes of max_size left while (cmng->max_size < cmng->size + size && g_queue_peek_tail (cmng->q_lru)) { entry = (struct _CacheEntry *) g_queue_peek_tail (cmng->q_lru); cache_mng_remove_file (cmng, entry->ino); } cmng->check_time = now; } context = cache_context_create (size, ctx); context->cb.store_cb = on_store_file_buf_cb; cache_mng_file_name (cmng, path, sizeof (path), ino); fd = open (path, O_WRONLY|O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH); if (fd < 0) { LOG_err (CMNG_LOG, INO_H"Failed to create / open file for writing! Path: %s", INO_T (ino), path); if (context->cb.store_cb) context->cb.store_cb (FALSE, context->user_ctx); cache_context_destroy (context); return; } res = pwrite(fd, buf, size, off); close (fd); entry = g_hash_table_lookup (cmng->h_entries, GUINT_TO_POINTER (ino)); if (!entry) { entry = cache_entry_create (ino); g_queue_push_head (cmng->q_lru, entry); entry->ll_lru = g_queue_peek_head_link (cmng->q_lru); g_hash_table_insert (cmng->h_entries, GUINT_TO_POINTER (ino), entry); } old_length = range_length (entry->avail_range); range_add (entry->avail_range, off, range_size); new_length = range_length (entry->avail_range); if (new_length >= old_length) cmng->size += new_length - old_length; else { LOG_err (CMNG_LOG, INO_H"New length is less than the old length !: %"G_GUINT64_FORMAT" <= %"G_GUINT64_FORMAT, INO_T (ino), new_length, old_length); } // update modification time entry->modification_time = time (NULL); context->success = (res == (ssize_t) size); LOG_debug (CMNG_LOG, INO_H"Written [%"OFF_FMT":%zu] bytes, result: %s", INO_T (ino), off, size, context->success ? "OK" : "Failed"); context->ev = event_new (application_get_evbase (cmng->app), -1, 0, cache_write_cb, context); // fire this event at once event_active (context->ev, 0, 0); event_add (context->ev, NULL); }