void ydb_sync(YDB ydb) { struct db *db = (struct db *) ydb; assert(db->magic == YDB_STRUCT_MAGIC); DB_LOCK(db); loglist_fsync(db->loglist); DB_UNLOCK(db); }
int ydb_get(YDB ydb, char *key, unsigned short key_sz, char *buf, int buf_sz) { struct db *db = (struct db *) ydb; assert(db->magic == YDB_STRUCT_MAGIC); DB_LOCK(db); struct item *item = tree_get(db->tree, key, key_sz); if(item == NULL) goto error; int needed = item->value_sz + MAX_PADDING + sizeof(struct ydb_value_record); if(buf_sz < needed) { log_error("ydb_get:buffer too small. is %i, should be at least %i", buf_sz, needed); goto error; } int r = loglist_get(db->loglist, item->logno, item->value_offset, item->value_sz, buf, buf_sz); if(r < 0) goto error; DB_UNLOCK(db); return(r); error: DB_UNLOCK(db); return(-1); }
/*----------------------------------------------------------------------------*/ static void __dbpool_mysql_close(ACL_DB_HANDLE *db_handle) { char myname[] = "__dbpool_mysql_close"; ACL_DB_POOL *db_pool; ACL_DB_POOL_MYSQL *mysql_pool; ACL_DB_HANDLE_MYSQL *mysql_handle = (ACL_DB_HANDLE_MYSQL *) db_handle; if (db_handle->status != ACL_DBH_STATUS_INUSE || mysql_handle->connection == NULL) { acl_msg_error("%s, %s(%d): status %s ACL_DBH_STATUS_INUSE, connection %s", __FILE__, myname, __LINE__, db_handle->status == ACL_DBH_STATUS_INUSE ? "=" : "!=", mysql_handle->connection ? "not null" : "null"); return; } db_pool = db_handle->parent; if (db_pool == NULL) acl_msg_fatal("%s, %s(%d): db_handle's parent is null", __FILE__, myname, __LINE__); mysql_pool = (ACL_DB_POOL_MYSQL *) db_pool; DB_LOCK(mysql_pool->mutex); __close_mysql_handle(mysql_handle); db_pool->db_inuse--; DB_UNLOCK(mysql_pool->mutex); }
void ydb_prefetch(YDB ydb, char **keys, unsigned short *key_szs, int items_counter) { struct db *db = (struct db *) ydb; assert(db->magic == YDB_STRUCT_MAGIC); struct item **items_start = (struct item **)malloc(sizeof(struct item_index *) * items_counter); struct item **items = items_start; DB_LOCK(db); int i; for(i=0; i < items_counter; i++, keys++, key_szs++) { char *key = *keys; int key_sz = *key_szs; struct item *item = tree_get(db->tree, key, key_sz); if(item) { *items = item; items++; } } DB_UNLOCK(db); int items_sz = items - items_start; qsort(items_start, items_sz, sizeof(struct item *), item_cmp); items = items_start; int fd = -1; int count = 0; int offset = 0; for(i=0; i < items_sz; i++, items++) { struct item *item = *items; struct log *log = slot_get(db->loglist, item->logno); size_t read_size = ROUND_UP(item->value_sz, PADDING) + sizeof(struct ydb_value_record); /* merge? */ if(fd == log->fd && (offset + count + 4096) >= item->value_offset) { count = (item->value_offset+read_size) - offset; }else{ if(fd != log->fd) { /* clear previous fadvices */ posix_fadvise(log->fd, 0, 0, POSIX_FADV_RANDOM); } if(fd != -1) { posix_fadvise(fd, offset, count, POSIX_FADV_WILLNEED); } fd = log->fd; count = read_size; offset = item->value_offset; } } if(fd != -1) { posix_fadvise(fd, offset, count, POSIX_FADV_WILLNEED); } free(items_start); }
int ydb_get_keys(YDB ydb, char *key, unsigned short key_sz, char *buf, int buf_sz) { struct db *db = (struct db *) ydb; assert(db->magic == YDB_STRUCT_MAGIC); DB_LOCK(db); int r = tree_get_keys(db->tree, key, key_sz, buf, buf_sz); DB_UNLOCK(db); return(r); }
int ydb_del(YDB ydb, char *key, unsigned short key_sz) { struct db *db = (struct db *) ydb; assert(db->magic == YDB_STRUCT_MAGIC); DB_LOCK(db); struct append_info af; af = loglist_append(db->loglist, key, key_sz, NULL, 0, FLAG_DELETE); tree_del(db->tree, key, key_sz, af.logno, af.record_offset); DB_UNLOCK(db); return(-1); }
int ydb_add(YDB ydb, char *key, unsigned short key_sz, char *value, unsigned int value_sz) { struct db *db = (struct db *) ydb; assert(db->magic == YDB_STRUCT_MAGIC); if(value_sz > MAX_VALUE_SIZE) return(-1); /* TODO: error handling on write? */ DB_LOCK(db); if(db_add(db, key, key_sz, value, value_sz) < 0) { value_sz = -1; goto release; } if(db->gc_finished) { gc_join(db); } release: DB_UNLOCK(db); return(value_sz); }
/*----------------------------------------------------------------------------*/ static void __dbpool_mysql_release(ACL_DB_HANDLE *db_handle) { char myname[] = "__dbpool_mysql_release"; ACL_DB_POOL *db_pool; ACL_DB_POOL_MYSQL *mysql_pool; ACL_DB_HANDLE_MYSQL *mysql_handle; int timeout_inter, ping_inter; mysql_handle = (ACL_DB_HANDLE_MYSQL *) db_handle; if (db_handle->status != ACL_DBH_STATUS_INUSE || mysql_handle->connection == NULL) { acl_msg_error("%s, %s(%d): status %s ACL_DBH_STATUS_INUSE, connection %s", __FILE__, myname, __LINE__, db_handle->status == ACL_DBH_STATUS_INUSE ? "=" : "!=", mysql_handle->connection ? "not null" : "null"); return; } db_pool = db_handle->parent; timeout_inter = db_pool->db_info.timeout_inter; ping_inter = db_pool->db_info.ping_inter; if (db_pool == NULL) acl_msg_fatal("%s, %s(%d): db_handle's parent is null", __FILE__, myname, __LINE__); mysql_pool = (ACL_DB_POOL_MYSQL *) db_pool; DB_LOCK(mysql_pool->mutex); db_handle->status = ACL_DBH_STATUS_READY; db_handle->timeout = time(NULL) + timeout_inter; db_handle->ping = time(NULL) + ping_inter; db_pool->db_inuse--; db_pool->db_ready++; DB_UNLOCK(mysql_pool->mutex); }
/*----------------------------------------------------------------------------*/ static ACL_DB_HANDLE *__dbpool_mysql_peek(ACL_DB_POOL *db_pool) { char myname[] = "__dbpool_mysql_peek"; ACL_DB_POOL_MYSQL *mysql_pool = (ACL_DB_POOL_MYSQL *) db_pool; ACL_DB_HANDLE_MYSQL *mysql_handle, *mysql_handle_slot = NULL; int i, n; time_t now; static time_t last_time; /* 因为在调用此函数时已经上锁, * 所以此处声明一静态变量是线程安全的. */ #undef RETURN #define RETURN(_x_) do { \ now = time(NULL); \ if (acl_msg_verbose && now - last_time > 5) { \ acl_msg_info("Database status: max = %d, idle = %d, busy = %d", \ db_pool->db_max, db_pool->db_ready, db_pool->db_inuse); \ last_time = now; \ } \ DB_UNLOCK(mysql_pool->mutex); \ return (_x_); \ } while (0) DB_LOCK(mysql_pool->mutex); if (time(NULL) >= mysql_pool->when_check) { int inter = db_pool->db_info.ping_inter > db_pool->db_info.timeout_inter ? db_pool->db_info.timeout_inter : db_pool->db_info.ping_inter; db_pool->dbh_check(db_pool); mysql_pool->when_check = time(NULL) + inter; } if (db_pool->db_inuse >= db_pool->db_max) { acl_msg_warn("%s, %s(%d): all connections be used, reached db_max(%d)", __FILE__, myname, __LINE__, db_pool->db_max); RETURN (NULL); } n = acl_array_size(mysql_pool->handles); /* lookup mysql connection from pool */ for (i = 0; i < n; i++) { mysql_handle = (ACL_DB_HANDLE_MYSQL *) acl_array_index(mysql_pool->handles, i); if (mysql_handle == NULL) continue; if (mysql_handle->handle.status == ACL_DBH_STATUS_READY) { mysql_handle->handle.status = ACL_DBH_STATUS_INUSE; db_pool->db_inuse++; db_pool->db_ready--; RETURN ((ACL_DB_HANDLE *) mysql_handle); } else if (mysql_handle->handle.status == ACL_DBH_STATUS_NULL && mysql_handle_slot == NULL) mysql_handle_slot = mysql_handle; } /* create new mysql connection */ mysql_handle = __open_mysql_handle(mysql_pool, mysql_handle_slot, &db_pool->db_info); if (mysql_handle == NULL) RETURN (NULL); mysql_handle->handle.status = ACL_DBH_STATUS_INUSE; db_pool->db_inuse++; RETURN ((ACL_DB_HANDLE *) mysql_handle); }