
/*
 * Copyright (C) 2010-2015 Alibaba Group Holding Limited
 */


#ifndef _NGX_HTTP_TFS_H_INCLUDED_
#define _NGX_HTTP_TFS_H_INCLUDED_


#include <ngx_core.h>
#include <ngx_http.h>
#include <ngx_tfs_common.h>
#include <ngx_http_tfs_json.h>
#include <ngx_http_tfs_protocol.h>
#include <ngx_http_tfs_restful.h>
#include <ngx_http_connection_pool.h>
#include <ngx_http_tfs_rc_server_info.h>
#include <ngx_http_tfs_block_cache.h>
#include <ngx_http_tfs_duplicate.h>
#include <ngx_http_tfs_raw_fsname.h>
#include <ngx_http_tfs_peer_connection.h>
#include <ngx_http_tfs_tair_helper.h>
#include <ngx_http_tfs_timers.h>


typedef ngx_table_elt_t *(*ngx_http_tfs_create_header_pt)
    (ngx_http_request_t *r);


typedef struct {
    ngx_str_t                      state_msg;
    ngx_int_t                      state;
} ngx_http_tfs_state_t;


typedef struct {
    uint32_t                       ds_count;
    ngx_http_tfs_inet_t           *ds_addrs;
    int32_t                        version;
    int32_t                        lease_id;
} ngx_http_tfs_block_info_t;


typedef struct {
    uint32_t                       block_id;
    uint64_t                       file_id;
    int64_t                        offset;  /* offset in the file */
    uint32_t                       size;
    uint32_t                       crc;
} NGX_PACKED ngx_http_tfs_segment_info_t;


typedef struct {
    u_char                         file_name[NGX_HTTP_TFS_FILE_NAME_LEN];
    int64_t                        offset;
    uint32_t                       size;
    uint32_t                       crc;
} NGX_PACKED ngx_http_tfs_tmp_segment_info_t;


struct ngx_http_tfs_segment_data_s {
    uint8_t                        cache_hit;
    ngx_http_tfs_segment_info_t    segment_info;
    /* read/write offset inside this segment */
    uint32_t                       oper_offset;
    /* read/write size inside this segment */
    uint32_t                       oper_size;
    union {
        uint64_t                   write_file_number;
    };
    ngx_http_tfs_block_info_t      block_info;
    ngx_uint_t                     ds_retry;
    ngx_uint_t                     ds_index;
    ngx_chain_t                   *data;
    ngx_chain_t                   *orig_data; /* for write retry */
} NGX_PACKED;


typedef struct {
    uint8_t                        still_have; /* for custom file */
    uint32_t                       cluster_id;
    uint32_t                       open_mode;
    /* not for large_file's data */
    int64_t                        file_offset;
    uint64_t                       left_length;
    uint64_t                       file_hole_size;
    uint32_t                       last_write_segment_index;
    uint32_t                       segment_index;
    uint32_t                       segment_count;
    ngx_http_tfs_segment_data_t   *segment_data;
    uint32_t                       curr_batch_count;
} NGX_PACKED ngx_http_tfs_file_t;


struct  ngx_http_tfs_upstream_s {
    ngx_str_t                      lock_file;
    ngx_msec_t                     rcs_interval;

    ngx_str_t                      rcs_zone_name;
    ngx_shm_zone_t                *rcs_shm_zone;
    ngx_http_tfs_rc_ctx_t         *rc_ctx;
    uint8_t                        rcserver_index;
    uint32_t                       rc_servers_count;
    uint64_t                       rc_servers[NGX_HTTP_TFS_MAX_RCSERVER_COUNT];

    /* upstream name and port */
    in_port_t                      port;
    ngx_str_t                      host;
    ngx_addr_t                    *ups_addr;

    struct sockaddr_in             local_addr;
    u_char                         local_addr_text[NGX_INET_ADDRSTRLEN];

    ngx_flag_t                     enable_rcs;

    ngx_http_tfs_timers_data_t    *timer_data;

    unsigned                       used:1;
};


struct  ngx_http_tfs_loc_conf_s {
    ngx_msec_t                     timeout;

    size_t                         max_temp_file_size;
    size_t                         temp_file_write_size;

    size_t                         busy_buffers_size_conf;

    uint64_t                       meta_root_server;
    ngx_http_tfs_meta_table_t      meta_server_table;

    ngx_http_tfs_upstream_t       *upstream;
};


typedef struct {

    ngx_log_t                     *log;
} ngx_http_tfs_srv_conf_t;


struct  ngx_http_tfs_main_conf_s {
    ngx_msec_t                     tfs_connect_timeout;
    ngx_msec_t                     tfs_send_timeout;
    ngx_msec_t                     tfs_read_timeout;

    ngx_msec_t                     tair_timeout;
    ngx_http_tfs_tair_instance_t   dup_instances[NGX_HTTP_TFS_MAX_CLUSTER_COUNT];

    size_t                         send_lowat;
    size_t                         buffer_size;
    size_t                         body_buffer_size;
    size_t                         busy_buffers_size;

    ngx_shm_zone_t                *block_cache_shm_zone;

    ngx_flag_t                     enable_remote_block_cache;
    ngx_http_tfs_tair_instance_t   remote_block_cache_instance;
    ngx_http_tfs_local_block_cache_ctx_t *local_block_cache_ctx;

    ngx_http_connection_pool_t    *conn_pool;

    uint32_t                       cluster_id;

    ngx_array_t                    upstreams;
};


typedef ngx_int_t (*tfs_peer_handler_pt)(ngx_http_tfs_t *t);
typedef void (*ngx_http_tfs_handler_pt)(ngx_http_request_t *r,
    ngx_http_tfs_t *t);
typedef ngx_int_t (*ngx_http_tfs_sub_process_pt)(ngx_http_tfs_t *t);


typedef struct {
    ngx_list_t                     headers;

    ngx_uint_t                     status_n;
    ngx_str_t                      status_line;

    ngx_table_elt_t               *status;
    ngx_table_elt_t               *date;
    ngx_table_elt_t               *server;
    ngx_table_elt_t               *connection;

    ngx_table_elt_t               *expires;
    ngx_table_elt_t               *etag;
    ngx_table_elt_t               *x_accel_expires;
    ngx_table_elt_t               *x_accel_redirect;
    ngx_table_elt_t               *x_accel_limit_rate;

    ngx_table_elt_t               *content_type;
    ngx_table_elt_t               *content_length;

    ngx_table_elt_t               *last_modified;
    ngx_table_elt_t               *location;
    ngx_table_elt_t               *accept_ranges;
    ngx_table_elt_t               *www_authenticate;

#if (NGX_HTTP_GZIP)
    ngx_table_elt_t               *content_encoding;
#endif

    off_t                          content_length_n;

    ngx_array_t                    cache_control;
} ngx_http_tfs_headers_in_t;


struct ngx_http_tfs_s {
    ngx_http_tfs_handler_pt        read_event_handler;
    ngx_http_tfs_handler_pt        write_event_handler;

    ngx_http_tfs_peer_connection_t *tfs_peer;
    ngx_http_tfs_peer_connection_t *tfs_peer_servers;
    uint8_t                       tfs_peer_count;

    ngx_http_tfs_loc_conf_t       *loc_conf;
    ngx_http_tfs_srv_conf_t       *srv_conf;
    ngx_http_tfs_main_conf_t      *main_conf;

    ngx_http_tfs_restful_ctx_t     r_ctx;

    ngx_output_chain_ctx_t         output;
    ngx_chain_writer_ctx_t         writer;

    ngx_chain_t                   *request_bufs;
    ngx_chain_t                   *send_body;
    ngx_pool_t                    *pool;

    ngx_buf_t                      header_buffer;

    ngx_chain_t                   *recv_chain;

    ngx_chain_t                   *out_bufs;
    ngx_chain_t                   *busy_bufs;
    ngx_chain_t                   *free_bufs;

    ngx_http_tfs_rcs_info_t       *rc_info_node;
    ngx_rbtree_node_t             *node;

    ngx_uint_t                     logical_cluster_index;
    ngx_uint_t                     rw_cluster_index;

    /* keep alive */
    ngx_queue_t                   *curr_ka_queue;

    /* header pointer */
    void                          *header;
    ngx_int_t                      header_size;

    tfs_peer_handler_pt            create_request;
    tfs_peer_handler_pt            input_filter;
    tfs_peer_handler_pt            retry_handler;
    tfs_peer_handler_pt            process_request_body;
    tfs_peer_handler_pt            finalize_request;
    tfs_peer_handler_pt            decline_handler;

    void                          *finalize_data;
    void                          *data;

    ngx_int_t                      request_sent;
    ngx_uint_t                     sent_size;
    off_t                          length;

    ngx_log_t                     *log;

    ngx_int_t                      parse_state;

    /* final file name */
    ngx_str_t                      file_name;

    ngx_int_t                      state;

    /* custom file */
    ngx_http_tfs_custom_meta_info_t meta_info;
    ngx_str_t                      last_file_path;
    int64_t                        last_file_pid;
    uint8_t                        last_file_type;
    ngx_int_t                     *dir_lens;
    ngx_int_t                      last_dir_level;
    uint16_t                       orig_action;
    ngx_array_t                    file_holes;

    ngx_http_tfs_headers_in_t      headers_in;

    /* delete */
    ngx_int_t                      group_count;
    ngx_int_t                      group_seq;

    /* name ip */
    ngx_http_tfs_inet_t            name_server_addr;
    ngx_str_t                      name_server_addr_text;

    ngx_http_tfs_json_gen_t       *json_output;

    ngx_uint_t                     status;
    ngx_str_t                      status_line;
    ngx_int_t                      tfs_status;

    uint64_t                       output_size;

    /* de-duplicate info */
    ngx_http_tfs_dedup_ctx_t       dedup_ctx;

    /* stat info */
    ngx_http_tfs_stat_info_t       stat_info;

    /* file info */
    ngx_chain_t                   *meta_segment_data;
    ngx_http_tfs_file_t            file;
    ngx_http_tfs_segment_head_t   *seg_head;
    ngx_http_tfs_raw_file_stat_t   file_stat;
    ngx_buf_t                     *readv2_rsp_tail_buf;
    uint8_t                        read_ver;
    uint8_t                        retry_count;

    /* block cache */
    ngx_http_tfs_block_cache_ctx_t block_cache_ctx;

    /* for parallel write segments */
    ngx_http_tfs_t                *parent;
    ngx_http_tfs_t                *next;
    ngx_http_tfs_t                *free_sts;
    ngx_http_tfs_sub_process_pt    sp_callback;
    uint32_t                       sp_count;
    uint32_t                       sp_done_count;
    uint32_t                       sp_fail_count;
    uint32_t                       sp_succ_count;
    uint32_t                       sp_curr;
    unsigned                       sp_ready:1;

    unsigned                       header_only:1;
    unsigned                       has_split_frag:1;
    /* for custrom file read */
    unsigned                       is_first_segment:1;

    unsigned                       use_dedup:1;
    unsigned                       is_stat_dup_file:1;
    unsigned                       is_large_file:1;
    unsigned                       is_process_meta_seg:1;
    unsigned                       retry_curr_ns:1;
    unsigned                       request_timeout:1;
    unsigned                       client_abort:1;
    unsigned                       is_rolling_back:1;
    unsigned                       header_sent:1;
};


ngx_int_t ngx_http_tfs_init(ngx_http_tfs_t *t);
void ngx_http_tfs_finalize_request(ngx_http_request_t *r,
    ngx_http_tfs_t *t, ngx_int_t rc);
void ngx_http_tfs_finalize_state(ngx_http_tfs_t *t, ngx_int_t rc);
ngx_int_t ngx_http_tfs_reinit(ngx_http_request_t *r, ngx_http_tfs_t *t);
ngx_int_t ngx_http_tfs_connect(ngx_http_tfs_t *t);
/* block cache related */
ngx_int_t ngx_http_tfs_lookup_block_cache(ngx_http_tfs_t *t);
ngx_int_t ngx_http_tfs_batch_lookup_block_cache(ngx_http_tfs_t *t);
void ngx_http_tfs_remove_block_cache(ngx_http_tfs_t *t,
    ngx_http_tfs_segment_data_t *segment_data);

ngx_int_t ngx_http_tfs_set_output_appid(ngx_http_tfs_t *t, uint64_t app_id);
void ngx_http_tfs_set_custom_initial_parameters(ngx_http_tfs_t *t);
ngx_int_t ngx_http_tfs_misc_ctx_init(ngx_http_tfs_t *t,
    ngx_http_tfs_rcs_info_t *rc_node);

/* dedup related */
ngx_int_t ngx_http_tfs_get_duplicate_info(ngx_http_tfs_t *t);
ngx_int_t ngx_http_tfs_set_duplicate_info(ngx_http_tfs_t *t);

/* sub process related */
ngx_int_t ngx_http_tfs_batch_process_start(ngx_http_tfs_t *t);
ngx_int_t ngx_http_tfs_batch_process_end(ngx_http_tfs_t *t);
ngx_int_t ngx_http_tfs_batch_process_next(ngx_http_tfs_t *t);


#endif /* _NGX_TFS_H_INCLUDED_ */
