From 9e0a40fee13134d47980f01c68ec3b10e0d31bc3 Mon Sep 17 00:00:00 2001 From: Michael Forney Date: Sun, 5 Jun 2016 17:25:36 -0700 Subject: [PATCH] Use a compact array and free list for requests --- sshfs.c | 126 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 80 insertions(+), 46 deletions(-) diff --git a/sshfs.c b/sshfs.c index d4d624d..92b893e 100644 --- a/sshfs.c +++ b/sshfs.c @@ -171,6 +171,17 @@ struct request { struct list_head list; }; +union request_entry { + struct request *req; + uintptr_t next; +}; + +struct request_table { + union request_entry *entries; + int len, cap; + uint32_t free; +}; + struct sshfs_io { int num_reqs; pthread_cond_t finished; @@ -253,7 +264,7 @@ struct sshfs { int slave; char *host; char *base_path; - GHashTable *reqtab; + struct request_table reqtab; pthread_mutex_t lock; pthread_mutex_t lock_write; int processing_thread_started; @@ -1171,12 +1182,6 @@ static int do_write(struct iovec *iov, size_t count) return 0; } -static uint32_t sftp_get_id(void) -{ - static uint32_t idctr; - return idctr++; -} - static void buf_to_iov(const struct buffer *buf, struct iovec *iov) { iov->iov_base = buf->p; @@ -1269,6 +1274,43 @@ static void request_free(struct request *req) g_free(req); } +static int request_table_insert(struct request_table *reqtab, struct request *req) +{ + union request_entry *entries; + size_t cap; + + if (reqtab->free) { + req->id = reqtab->free; + reqtab->free = reqtab->entries[req->id-1].next >> 1; + } else { + if (reqtab->len == reqtab->cap) { + cap = reqtab->cap * 2 + 1; + entries = realloc(reqtab->entries, cap * sizeof(reqtab->entries[0])); + if (!entries) + return -1; + reqtab->cap = cap; + reqtab->entries = entries; + } + req->id = ++reqtab->len; + } + + reqtab->entries[req->id-1].req = req; + return 0; +} + +static struct request *request_table_lookup(struct request_table *reqtab, uint32_t id) +{ + if (reqtab->entries[id-1].next & 1) + return NULL; + return reqtab->entries[id-1].req; +} + +static void request_table_remove(struct request_table *reqtab, uint32_t id) +{ + reqtab->entries[id-1].next = (reqtab->free << 1) | 1; + reqtab->free = id; +} + static void chunk_free(struct read_chunk *chunk) { while (!list_empty(&chunk->reqs)) { @@ -1298,22 +1340,6 @@ static void chunk_put_locked(struct read_chunk *chunk) pthread_mutex_unlock(&sshfs.lock); } -static int clean_req(void *key_, struct request *req, gpointer user_data_) -{ - (void) key_; - (void) user_data_; - - req->error = -EIO; - if (req->want_reply) - sem_post(&req->ready); - else { - if (req->end_func) - req->end_func(req); - request_free(req); - } - return TRUE; -} - static int process_one_request(void) { int res; @@ -1330,8 +1356,7 @@ static int process_one_request(void) return -1; pthread_mutex_lock(&sshfs.lock); - req = (struct request *) - g_hash_table_lookup(sshfs.reqtab, GUINT_TO_POINTER(id)); + req = request_table_lookup(&sshfs.reqtab, id); if (req == NULL) fprintf(stderr, "request %i not found\n", id); else { @@ -1343,7 +1368,7 @@ static int process_one_request(void) sshfs.outstanding_len <= sshfs.max_outstanding_len) { pthread_cond_broadcast(&sshfs.outstanding_cond); } - g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id)); + request_table_remove(&sshfs.reqtab, id); } pthread_mutex_unlock(&sshfs.lock); if (req != NULL) { @@ -1404,6 +1429,9 @@ static void close_conn(void) static void *process_requests(void *data_) { + int i; + struct request *req; + (void) data_; while (1) { @@ -1414,7 +1442,20 @@ static void *process_requests(void *data_) pthread_mutex_lock(&sshfs.lock); sshfs.processing_thread_started = 0; close_conn(); - g_hash_table_foreach_remove(sshfs.reqtab, (GHRFunc) clean_req, NULL); + for (i = 0; i < sshfs.reqtab.len; ++i) { + if (sshfs.reqtab.entries[i].next & 1) + continue; + req = sshfs.reqtab.entries[i].req; + req->error = -EIO; + if (req->want_reply) + sem_post(&req->ready); + else { + if (req->end_func) + req->end_func(req); + request_free(req); + } + request_table_remove(&sshfs.reqtab, i + 1); + } sshfs.connver ++; sshfs.outstanding_len = 0; pthread_cond_broadcast(&sshfs.outstanding_cond); @@ -1562,7 +1603,6 @@ static int sftp_error_to_errno(uint32_t error) static void sftp_detect_uid() { int flags; - uint32_t id = sftp_get_id(); uint32_t replid; uint8_t type; struct buffer buf; @@ -1572,7 +1612,7 @@ static void sftp_detect_uid() buf_init(&buf, 5); buf_add_string(&buf, "."); buf_to_iov(&buf, &iov[0]); - if (sftp_send_iov(SSH_FXP_STAT, id, iov, 1) == -1) + if (sftp_send_iov(SSH_FXP_STAT, 0, iov, 1) == -1) goto out; buf_clear(&buf); if (sftp_read(&type, &buf) == -1) @@ -1583,7 +1623,7 @@ static void sftp_detect_uid() } if (buf_get_uint32(&buf, &replid) == -1) goto out; - if (replid != id) { + if (replid != 0) { fprintf(stderr, "bad reply ID\n"); goto out; } @@ -1618,7 +1658,6 @@ out: static int sftp_check_root(const char *base_path) { int flags; - uint32_t id = sftp_get_id(); uint32_t replid; uint8_t type; struct buffer buf; @@ -1630,7 +1669,7 @@ static int sftp_check_root(const char *base_path) buf_init(&buf, 0); buf_add_string(&buf, remote_dir); buf_to_iov(&buf, &iov[0]); - if (sftp_send_iov(SSH_FXP_LSTAT, id, iov, 1) == -1) + if (sftp_send_iov(SSH_FXP_LSTAT, 0, iov, 1) == -1) goto out; buf_clear(&buf); if (sftp_read(&type, &buf) == -1) @@ -1641,7 +1680,7 @@ static int sftp_check_root(const char *base_path) } if (buf_get_uint32(&buf, &replid) == -1) goto out; - if (replid != id) { + if (replid != 0) { fprintf(stderr, "bad reply ID\n"); goto out; } @@ -1831,7 +1870,6 @@ static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count, struct request **reqp) { int err; - uint32_t id; struct request *req = g_new0(struct request, 1); req->want_reply = want_reply; @@ -1842,8 +1880,6 @@ static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count, pthread_mutex_lock(&sshfs.lock); if (begin_func) begin_func(req); - id = sftp_get_id(); - req->id = id; err = start_processing_thread(); if (err) { pthread_mutex_unlock(&sshfs.lock); @@ -1854,21 +1890,24 @@ static int sftp_request_send(uint8_t type, struct iovec *iov, size_t count, while (sshfs.outstanding_len > sshfs.max_outstanding_len) pthread_cond_wait(&sshfs.outstanding_cond, &sshfs.lock); - g_hash_table_insert(sshfs.reqtab, GUINT_TO_POINTER(id), req); + if (request_table_insert(&sshfs.reqtab, req) < 0) + abort(); if (sshfs.debug) { gettimeofday(&req->start, NULL); sshfs.num_sent++; sshfs.bytes_sent += req->len; } - DEBUG("[%05i] %s\n", id, type_name(type)); + DEBUG("[%05i] %s\n", req->id, type_name(type)); pthread_mutex_unlock(&sshfs.lock); err = -EIO; - if (sftp_send_iov(type, id, iov, count) == -1) { + if (sftp_send_iov(type, req->id, iov, count) == -1) { gboolean rmed; pthread_mutex_lock(&sshfs.lock); - rmed = g_hash_table_remove(sshfs.reqtab, GUINT_TO_POINTER(id)); + rmed = !!request_table_lookup(&sshfs.reqtab, req->id); + if (rmed) + request_table_remove(&sshfs.reqtab, req->id); pthread_mutex_unlock(&sshfs.lock); if (!rmed && !want_reply) { @@ -2041,7 +2080,7 @@ static int sftp_readdir_send(struct request **req, struct buffer *handle) static int sshfs_req_pending(struct request *req) { - if (g_hash_table_lookup(sshfs.reqtab, GUINT_TO_POINTER(req->id))) + if (request_table_lookup(&sshfs.reqtab, req->id)) return 1; else return 0; @@ -3312,11 +3351,6 @@ static int processing_init(void) pthread_mutex_init(&sshfs.lock, NULL); pthread_mutex_init(&sshfs.lock_write, NULL); pthread_cond_init(&sshfs.outstanding_cond, NULL); - sshfs.reqtab = g_hash_table_new(NULL, NULL); - if (!sshfs.reqtab) { - fprintf(stderr, "failed to create hash table\n"); - return -1; - } return 0; } -- 2.24.0