Example #1
0
ngx_int_t
ngx_http_tfs_duplicate_check_filename(ngx_str_t *dup_file_name, ngx_http_tfs_raw_fsname_t* fsname)
{
    ngx_int_t                    rc;
    ngx_str_t                    dup_file_suffix = ngx_null_string;
    ngx_http_tfs_raw_fsname_t    dup_fsname;

    rc = ngx_http_tfs_raw_fsname_parse(dup_file_name, &dup_file_suffix, &dup_fsname);
    if (rc == NGX_OK) {
        if (fsname->cluster_id == dup_fsname.cluster_id
            && fsname->file.block_id == dup_fsname.file.block_id
            && fsname->file.seq_id == dup_fsname.file.seq_id
            && fsname->file.suffix == dup_fsname.file.suffix)
        {
            return NGX_OK;
        }
    }

    return NGX_ERROR;
}
Example #2
0
static ngx_int_t
ngx_http_restful_parse_action_raw(ngx_http_request_t *r,
    ngx_http_tfs_restful_ctx_t *ctx)
{
    ngx_int_t  rc;
    ngx_str_t  arg_value;

    switch(r->method) {
    case NGX_HTTP_GET:
        if (ngx_http_arg(r, (u_char *) "suffix", 6, &arg_value) == NGX_OK) {
            ctx->file_suffix = arg_value;
        }

        rc = ngx_http_tfs_raw_fsname_parse(&ctx->file_path_s, &ctx->file_suffix,
                                           &ctx->fsname);
        if (rc != NGX_OK) {
            return NGX_HTTP_BAD_REQUEST;
        }

        if (ngx_http_arg(r, (u_char *) "type", 4, &arg_value) == NGX_OK) {
            if (arg_value.len != 1) {
                return NGX_HTTP_BAD_REQUEST;
            }
            ctx->read_stat_type = ngx_atoi(arg_value.data, arg_value.len);
            /* normal_read/stat(0) or force_read/stat(1) */
            if (ctx->read_stat_type == NGX_ERROR
                || (ctx->read_stat_type != NGX_HTTP_TFS_READ_STAT_NORMAL
                    && ctx->read_stat_type != NGX_HTTP_TFS_READ_STAT_FORCE))
            {
                return NGX_HTTP_BAD_REQUEST;
            }
        }
        if (ctx->meta) {
            ctx->action.code = NGX_HTTP_TFS_ACTION_STAT_FILE;
            ngx_str_set(&ctx->action.msg, "stat_file");

        } else {
            ctx->action.code = NGX_HTTP_TFS_ACTION_READ_FILE;
            ngx_str_set(&ctx->action.msg, "read_file");
            if (ngx_http_arg(r, (u_char *) "offset", 6, &arg_value) == NGX_OK) {
                ctx->offset = ngx_http_tfs_atoll(arg_value.data, arg_value.len);
                if (ctx->offset == NGX_ERROR) {
                    return NGX_HTTP_BAD_REQUEST;
                }
            }

            if (ngx_http_arg(r, (u_char *) "size", 4, &arg_value) == NGX_OK) {
                rc = ngx_http_tfs_atoull(arg_value.data,
                                         arg_value.len,
                                         (unsigned long long *)&ctx->size);
                if (rc == NGX_ERROR) {
                    return NGX_HTTP_BAD_REQUEST;
                }

                if (ctx->size == 0) {
                    return NGX_HTTP_BAD_REQUEST;
                }

                return NGX_OK;
            }

            ctx->size = NGX_HTTP_TFS_MAX_SIZE;
        }
        break;

    case NGX_HTTP_POST:
        ctx->action.code = NGX_HTTP_TFS_ACTION_WRITE_FILE;
        if (ngx_http_arg(r, (u_char *) "suffix", 6, &arg_value) == NGX_OK) {
            ctx->file_suffix = arg_value;
        }

        if (ngx_http_arg(r, (u_char *) "simple_name", 11, &arg_value)
            == NGX_OK)
        {
            if (arg_value.len != 1) {
                return NGX_HTTP_BAD_REQUEST;
            }
            ctx->simple_name = ngx_atoi(arg_value.data, arg_value.len);
            if (ctx->simple_name == NGX_ERROR
                || (ctx->simple_name != NGX_HTTP_TFS_NO
                    && ctx->simple_name != NGX_HTTP_TFS_YES))
            {
                return NGX_HTTP_BAD_REQUEST;
            }
        }

        if (ngx_http_arg(r, (u_char *) "large_file", 10, &arg_value)
            == NGX_OK)
        {
            if (arg_value.len != 1) {
                return NGX_HTTP_BAD_REQUEST;
            }
            ctx->large_file = ngx_atoi(arg_value.data, arg_value.len);
            if (ctx->large_file == NGX_ERROR
                || (ctx->large_file != NGX_HTTP_TFS_NO
                    && ctx->large_file != NGX_HTTP_TFS_YES))
            {
                return NGX_HTTP_BAD_REQUEST;
            }
        }

        if (ngx_http_arg(r, (u_char *) "meta_segment", 12, &arg_value)
            == NGX_OK)
        {
            if (arg_value.len != 1) {
                return NGX_HTTP_BAD_REQUEST;
            }
            ctx->write_meta_segment = ngx_atoi(arg_value.data, arg_value.len);
            if (ctx->write_meta_segment == NGX_ERROR
                || (ctx->write_meta_segment != NGX_HTTP_TFS_NO
                    && ctx->write_meta_segment != NGX_HTTP_TFS_YES))
            {
                return NGX_HTTP_BAD_REQUEST;
            }
        }

        if (ngx_http_arg(r, (u_char *) "no_dedup", 8, &arg_value) == NGX_OK) {
            if (arg_value.len != 1) {
                return NGX_HTTP_BAD_REQUEST;
            }
            ctx->no_dedup = ngx_atoi(arg_value.data, arg_value.len);
            if (ctx->no_dedup == NGX_ERROR
                || (ctx->no_dedup != NGX_HTTP_TFS_NO
                    && ctx->no_dedup != NGX_HTTP_TFS_YES))
            {
                return NGX_HTTP_BAD_REQUEST;
            }
        }

        ngx_str_set(&ctx->action.msg, "write_file");
        break;

    case NGX_HTTP_DELETE:
        ctx->action.code = NGX_HTTP_TFS_ACTION_REMOVE_FILE;
        ngx_str_set(&ctx->action.msg, "remove_file");

        /* for outer user use */
        if (ngx_http_arg(r, (u_char *) "hide", 4, &arg_value) == NGX_OK) {
            if (arg_value.len != 1) {
                return NGX_HTTP_BAD_REQUEST;
            }
            ctx->unlink_type = ngx_atoi(arg_value.data, arg_value.len);
            /* hide(1) or reveal(0)*/
            if (ctx->unlink_type == NGX_ERROR
                || (ctx->unlink_type != 0 && ctx->unlink_type != 1))
            {
                return NGX_HTTP_BAD_REQUEST;
            }
            /* convert to actual type */
            if (ctx->unlink_type == 1) {
                ctx->unlink_type = NGX_HTTP_TFS_UNLINK_CONCEAL;

            } else {
                ctx->unlink_type = NGX_HTTP_TFS_UNLINK_REVEAL;
            }
        }

        if (ngx_http_arg(r, (u_char *) "type", 4, &arg_value) == NGX_OK) {
            if (arg_value.len != 1) {
                return NGX_HTTP_BAD_REQUEST;
            }
            ctx->unlink_type = ngx_atoi(arg_value.data, arg_value.len);
            /* del(0) or undel(2) or hide(4) or reveal(6)*/
            if (ctx->unlink_type == NGX_ERROR
                || (ctx->unlink_type != NGX_HTTP_TFS_UNLINK_DELETE
                    && ctx->unlink_type != NGX_HTTP_TFS_UNLINK_UNDELETE
                    && ctx->unlink_type != NGX_HTTP_TFS_UNLINK_CONCEAL
                    && ctx->unlink_type != NGX_HTTP_TFS_UNLINK_REVEAL))
            {
                return NGX_HTTP_BAD_REQUEST;
            }
        }

        if (ngx_http_arg(r, (u_char *) "suffix", 6, &arg_value) == NGX_OK) {
            ctx->file_suffix = arg_value;
        }

        rc = ngx_http_tfs_raw_fsname_parse(&ctx->file_path_s, &ctx->file_suffix,
                                           &ctx->fsname);
        if (rc != NGX_OK) {
            return NGX_HTTP_BAD_REQUEST;
        }

        /* large file not support UNDELETE */
        if ((ctx->fsname.file_type == NGX_HTTP_TFS_LARGE_FILE_TYPE)
            && ctx->unlink_type == NGX_HTTP_TFS_UNLINK_UNDELETE)
        {
            return NGX_HTTP_BAD_REQUEST;
        }
        break;

    case NGX_HTTP_HEAD:
        if (ngx_http_arg(r, (u_char *) "suffix", 6, &arg_value) == NGX_OK) {
            ctx->file_suffix = arg_value;
        }

        rc = ngx_http_tfs_raw_fsname_parse(&ctx->file_path_s, &ctx->file_suffix,
                                           &ctx->fsname);
        if (rc != NGX_OK) {
            return NGX_HTTP_BAD_REQUEST;
        }

        if (ngx_http_arg(r, (u_char *) "type", 4, &arg_value) == NGX_OK) {
            if (arg_value.len != 1) {
                return NGX_HTTP_BAD_REQUEST;
            }
            ctx->read_stat_type = ngx_atoi(arg_value.data, arg_value.len);
            /* normal_read/stat(0) or force_read/stat(1) */
            if (ctx->read_stat_type == NGX_ERROR
                || (ctx->read_stat_type != NGX_HTTP_TFS_READ_STAT_NORMAL
                    && ctx->read_stat_type != NGX_HTTP_TFS_READ_STAT_FORCE))
            {
                return NGX_HTTP_BAD_REQUEST;
            }
        }
        ctx->action.code = NGX_HTTP_TFS_ACTION_STAT_FILE;
        ngx_str_set(&ctx->action.msg, "stat_file");
        ctx->chk_exist = NGX_HTTP_TFS_YES;
        break;

    case NGX_HTTP_PUT:
        ctx->action.code = NGX_HTTP_TFS_ACTION_WRITE_FILE;
        if (ngx_http_arg(r, (u_char *) "suffix", 6, &arg_value) == NGX_OK) {
            ctx->file_suffix = arg_value;
        }

        if (ngx_http_arg(r, (u_char *) "simple_name", 11, &arg_value)
            == NGX_OK)
        {
            if (arg_value.len != 1) {
                return NGX_HTTP_BAD_REQUEST;
            }
            ctx->simple_name = ngx_atoi(arg_value.data, arg_value.len);
            if (ctx->simple_name == NGX_ERROR
                || (ctx->simple_name != NGX_HTTP_TFS_NO
                    && ctx->simple_name != NGX_HTTP_TFS_YES))
            {
                return NGX_HTTP_BAD_REQUEST;
            }
        }

        if (ctx->file_path_s.data == NULL) {
            return NGX_HTTP_BAD_REQUEST;
        }

        /* large file not support update */
        if (ngx_http_arg(r, (u_char *) "large_file", 10, &arg_value) == NGX_OK) {
            return NGX_HTTP_BAD_REQUEST;
        }

        rc = ngx_http_tfs_raw_fsname_parse(&ctx->file_path_s, &ctx->file_suffix,
                                           &ctx->fsname);
        /* large file not support update */
        if (rc != NGX_OK
            || (ctx->fsname.file_type == NGX_HTTP_TFS_LARGE_FILE_TYPE))
        {
            return NGX_HTTP_BAD_REQUEST;
        }

        ctx->is_raw_update = NGX_HTTP_TFS_YES;
        ngx_str_set(&ctx->action.msg, "write_file");
        break;

    default:
        return NGX_HTTP_BAD_REQUEST;
    }

    return NGX_OK;
}
static void
ngx_http_tfs_dedup_callback(ngx_http_tfs_dedup_ctx_t *ctx, ngx_int_t rc)
{
    ngx_http_tfs_t           *t;
    ngx_http_tfs_rcs_info_t  *rc_info;

    t = ctx->data;
    rc_info = t->rc_info_node;

    switch (t->r_ctx.action.code) {
    case NGX_HTTP_TFS_ACTION_REMOVE_FILE:
        switch(t->state) {
        case NGX_HTTP_TFS_STATE_REMOVE_READ_META_SEGMENT:
            /* exist in tair */
            if (rc == NGX_OK) {
                /* check file name */
                rc = ngx_http_tfs_dedup_check_filename(&ctx->dup_file_name,
                                                       &t->r_ctx.fsname);
                if (rc == NGX_OK) {
                    /* file name match, modify ref count and save tair */
                    if (t->r_ctx.unlink_type == NGX_HTTP_TFS_UNLINK_DELETE) {
                        if (--ctx->file_ref_count <= 0) {
                            /* if ref count is 0,
                             * remove key from tair then unlink file
                             */
                            t->state = NGX_HTTP_TFS_STATE_REMOVE_GET_BLK_INFO;
                            t->is_stat_dup_file = NGX_HTTP_TFS_NO;
                            t->tfs_peer->body_buffer = ctx->save_body_buffer;
                            ctx->file_data = t->meta_segment_data;
                            rc = ngx_http_tfs_dedup_remove(ctx, t->pool,
                                                           t->log);
                            /* do not care delete tair fail,
                             * go on unlinking file
                             */
                            if (rc == NGX_ERROR) {
                                ngx_http_tfs_finalize_state(t, NGX_OK);
                            }

                            return;
                        }

                        /* file_ref_count > 0, just save tair */
                        t->state = NGX_HTTP_TFS_STATE_REMOVE_DONE;
                        ctx->file_data = t->meta_segment_data;
                        rc = ngx_http_tfs_dedup_set(ctx, t->pool, t->log);
                        /* do not care save tair fail, return success */
                        if (rc == NGX_ERROR) {
                            ngx_http_tfs_finalize_state(t, NGX_DONE);
                        }

                        return;
                    }
                }

                /* file name not match, unlink file */
                t->tfs_peer->body_buffer = ctx->save_body_buffer;
                t->state = NGX_HTTP_TFS_STATE_REMOVE_GET_BLK_INFO;
                t->is_stat_dup_file = NGX_HTTP_TFS_NO;
                ngx_http_tfs_finalize_state(t, NGX_OK);

                return;
            }

            /* not exist in tair, unlink file */
            t->tfs_peer->body_buffer = ctx->save_body_buffer;
            t->state = NGX_HTTP_TFS_STATE_REMOVE_GET_BLK_INFO;
            t->is_stat_dup_file = NGX_HTTP_TFS_NO;
            ngx_http_tfs_finalize_state(t, NGX_OK);
            return;
        case NGX_HTTP_TFS_STATE_REMOVE_GET_BLK_INFO:
        case NGX_HTTP_TFS_STATE_REMOVE_DELETE_DATA:
            ngx_http_tfs_finalize_state(t, NGX_OK);
            return;
        case NGX_HTTP_TFS_STATE_REMOVE_DONE:
            ngx_http_tfs_finalize_state(t, NGX_DONE);
            return;
        }
        break;
    case NGX_HTTP_TFS_ACTION_WRITE_FILE:
        switch(t->state) {
        case NGX_HTTP_TFS_STATE_WRITE_CLUSTER_ID_NS:
        case NGX_HTTP_TFS_STATE_WRITE_GET_BLK_INFO:
            /* exist in tair */
            if (rc == NGX_OK) {
                /* check suffix */
                rc = ngx_http_tfs_dedup_check_suffix(&ctx->dup_file_name,
                                                     &t->r_ctx.file_suffix);
                if (rc == NGX_OK) {
                    /* suffix match, need to stat file */
                    rc = ngx_http_tfs_raw_fsname_parse(&ctx->dup_file_name,
                                                       &ctx->dup_file_suffix,
                                                       &t->r_ctx.fsname);
                    if (rc == NGX_OK) {
                        t->file.cluster_id = t->r_ctx.fsname.cluster_id;
                        t->is_stat_dup_file = NGX_HTTP_TFS_YES;
                        t->state = NGX_HTTP_TFS_STATE_WRITE_GET_BLK_INFO;
                    }

                } else {
                    /* suffix not match, need save new tfs file,
                     * do not save tair
                     */
                    t->use_dedup = NGX_HTTP_TFS_NO;
                }
            } /* not exist in tair need save new tfs file and tair */

            /* need reset meta segment */
            rc = ngx_http_tfs_get_meta_segment(t);
            if (rc != NGX_OK) {
                ngx_log_error(NGX_LOG_ERR, t->log, 0,
                              "tfs get meta segment failed");
                ngx_http_tfs_finalize_request(t->data, t,
                                              NGX_HTTP_INTERNAL_SERVER_ERROR);
                return;
            }

            /* lookup block cache */
            if (t->is_stat_dup_file) {
                /* dedup write may need to stat file */
                if (rc_info->use_remote_block_cache) {
                    rc = ngx_http_tfs_get_remote_block_cache_instance(
                              &t->block_cache_ctx.remote_ctx,
                              &rc_info->remote_block_cache_info);
                    if (rc == NGX_ERROR) {
                        ngx_log_error(NGX_LOG_ERR, t->log, 0,
                                     "get remote block cache instance failed.");

                    } else {
                        t->block_cache_ctx.use_cache |=
                            NGX_HTTP_TFS_REMOTE_BLOCK_CACHE;
                    }
                }

                ngx_http_tfs_lookup_block_cache(t);

                return;
            }

            ngx_http_tfs_finalize_state(t, NGX_OK);
            break;
        case NGX_HTTP_TFS_STATE_WRITE_STAT_DUP_FILE:
            if (rc == NGX_OK) {
                t->state = NGX_HTTP_TFS_STATE_WRITE_DONE;
                ngx_http_tfs_finalize_state(t, NGX_DONE);

            } else {
                /* save tair(add ref count) failed,
                 * need save new tfs file, do not save tair
                 */
                t->state = NGX_HTTP_TFS_STATE_WRITE_CLUSTER_ID_NS;
                t->is_stat_dup_file = NGX_HTTP_TFS_NO;
                t->use_dedup = NGX_HTTP_TFS_NO;
                /* need reset output buf */
                t->out_bufs = NULL;
                /* need reset block id and file id */
                t->file.segment_data[0].segment_info.block_id = 0;
                t->file.segment_data[0].segment_info.file_id = 0;
                ngx_http_tfs_finalize_state(t, NGX_OK);
            }
            break;
        case NGX_HTTP_TFS_STATE_WRITE_DONE:
            ngx_http_tfs_finalize_state(t, NGX_DONE);
            break;
        }
    }
    return;
}