thrift 源码学习 一

1. thrift代码整体流程

1.1. 入口函数main

  • 如果输入gen,则添加到generator_strings中;初始化各个全局类型变量
  • parse(program,null)解析程序
  • generate(program,generator_strings)生成目标代码
  • 释放全局变量

作者有意思的代码注释:(*^__^*)

 // Clean up. Who am I kidding... this program probably orphans heap memory
  // all over the place, but who cares because it is about to exit and it is
  // all referenced and used by this wacky parse tree up until now anyways.

1.2. 解析函数 parse

  • 常量不能是void类型
  • inucde方式,yyparse词法分析;解析的结果放到t_program*  parogram这个参数中
    • program->get_includes: thrift.yy中

1.3. 代码生成 generate

  • 先得到所有的include文件,依次调用generate
  • 对每种指定的目标语言:
    • get_generator(program,options)
    • 参数options是语言参数,':'前是语言名,后面是参数值,每个参数通过','分割,参数值用'='连接
    • get_generator_map,得到所有的语言生成器名称,然后找到从options中得到的语言
    • get_generator(program, parsed_options, options) parsed_options是刚才解析options得到的键值对应的数组
    • generate_program
    • init_generator
      • 初始化文件路径
      • 初始化文件:xxxType,及其头部信息,php有<?php
    • generate_enum
      • 类名:final class xxx {
      • 常量:const
      • 静态结构体:static public $__names = array(xxx => xxx)
    • generate_typedef php中不存在类型定义,所以这里函数没有设置
    • generate_forward_declaration php中不需要声明结构、联合体等,所以也没有这部分代码
    • generate_xception/generate_struct
      • 类的声明,包括公共变量、静态变量
      • 构造函数、getName函数
      • read函数、write函数
      • _validateForWrite/Read函数,其中包括抛出异常的代码
    • generate_consts
      • 定义final类,静态保护变量、函数
    • generate_service
      • 生成服务类
      • 生成客户端类dump_docstrings(program)

 

2. 客户端、服务端数据不一致问题 

 

2.1. 两端定义的field标识不同

 

    代码在generate_enum部分可以找到对应:生成xx_type文件中的构造函数中结构定义代码

void t_php_generator::generate_php_struct_spec(ofstream& out, t_struct* tstruct) {
  ......
  const vector<t_field*>& members = tstruct->get_members();
  vector<t_field*>::const_iterator m_iter;
 
  for (m_iter = members.begin(); m_iter != members.end(); ++m_iter) {
    t_type* t = get_true_type((*m_iter)->get_type());
    indent(out) << (*m_iter)->get_key() << " => array(" << endl;
    indent_up();
    out <<indent() << "'var' => '" << (*m_iter)->get_name() << "'," << endl;
    generate_php_type_spec(out, t);
    indent(out) << ")," << endl;
    indent_down();
  }
   .......

    根据上面代码,生成如下php代码

public function __construct($vals=null) {
  if (!isset(self::$_TSPEC)) {
    self::$_TSPEC = array(
        1 => array(
          'var' => 'query',
        'type' => TType::STRING,
          ), 
      2 => array(
        'var' => 'cityid',
        'type' => TType::I32,
        ), 
        ......
  }  
}

    thrift的sever与client参数在传递过程中,是按照thrift文件中的field的顺序放入,field顺序是按照每个元素前面标识的大小排序:

bool t_struct::append(t_field* elem) {
    typedef members_type::iterator iter_type;
    std::pair<iter_type, iter_type> bounds = std::equal_range(
            members_in_id_order_.begin(), members_in_id_order_.end(), elem, t_field::key_compare()
        );
    ......
    members_.push_back(elem);
    ......
    return true;
  }
 
struct t_field::key_compare {
    bool operator()(t_field const * const & a, t_field const * const & b) {
      return a->get_key() < b->get_key();
    }
  };

2.2. 没有定义这个域的标识参数

找到thrift.yy文件,这里面根据flex&bison定义程序

Field:
  CaptureDocText FieldIdentifier FieldRequiredness FieldType FieldReference tok_identifier FieldValue XsdOptional XsdNillable XsdAttributes TypeAnnotations CommaOrSemicolonOptional
    {
      pdebug("tok_int_constant : Field -> FieldType tok_identifier");
      if ($2.auto_assigned) {
        pwarning(1, "No field key specified for %s, resulting protocol may have conflicts or not be backwards compatible!\n", $6);
        if (g_strict >= 192) {
          yyerror("Implicit field keys are deprecated and not allowed with -strict");
          exit(1);
        }
      }
      validate_simple_identifier($6);
      $$ = new t_field($4, $6, $2.value);
      ......
    }

 

posted @ 2014-08-27 09:39  settingsun1225  阅读(449)  评论(0编辑  收藏  举报