分包问题说明

由于tcp网络缓冲区大小的限制等因素,当响应包超过256KB,tcaplus后端会触发分包。但保证分包不会切分单个记录(不管这个记录多大),例如,响应包的3个记录分别是10KB、251KB、1MB,会分为2个包返回,即(10KB、251KB)和(1MB)。

1. 分包命令字

一般多包返回的命令字(一次读多条记录,或者一次写多条记录同时设置了ResultFlag返回旧记录)都有可能触发分包,所以需要判断分包场景

  • BatchGet,批量查询,超过256KB必然分包
  • BatchUpdate、BatchReplace、BatchDelete,批量修改或删除,设置返回旧记录的flag时,会返回批量的旧记录,默认不分包
  • GetByPartKey,通过本地索引查询,返回批量记录,超过256KB必然分包
  • UpdateByPartKey,DeleteByPartKey,会返回更新或删除的key,超过256KB必然分包
  • ListGetAll,List表查询List Key下所有的记录,默认不分包
  • ListGetBatch,List表查询List key下的批量记录,默认不分包
  • ListReplaceBatch、ListDeletBatch、ListAddAfterBatch修改或删除ListKey下的批量元素,设置返回旧记录的flag时,会返回批量的旧记录,默认不分包
  • 全局索引查询,当表配置了全局索引,可通过SQL查询返回批量的记录,超过256KB必然分包

总之方便记忆:

  • 要分包,request显示调用pstRequest->SetMultiResponseFlag(1);
  • 不要分包,request显示调用pstRequest->SetMultiResponseFlag(0); //BatchGet GetByPartKey UpdateByPartKey DeleteByPartKey 全局索引查询,必然分包,设置无效

2. 分包处理

对于分包返回的命令字需要特殊处理

  • 请求处理,在发送请求时需要设置下允许分包标记,有些请求默认没有设置分包标记,所以用户需要手动调用允许分包,否则不会分包,超过256k的包会丢掉(必然分包的除外)

      TcaplusService::TcaplusServiceRequest* pstRequest = g_stTcapSvr.GetRequest(TABLE_NAME);
      if (NULL == pstRequest)
      {
          tlog_error(g_pstLogHandler, 0, 0, "g_stTcapSvr.GetRequest(%s) failed.", TABLE_NAME);
          return -1;
      }
      int32_t iRet = pstRequest->Init(TCAPLUS_API_BATCH_GET_REQ, NULL, 0, 0, 0, 0);
      if(0 != iRet)
      {
          tlog_error(g_pstLogHandler, 0, 0, "pstRequest->Init(TCAPLUS_API_BATCH_GET_REQ) failed, iRet: %d.", iRet);
          return iRet;
      }
      //可以设置异步ID,响应带回
      uint64_t asyncId = 99;
      pstRequest->SetAsyncID(asyncId);
    
      //request在init之后设置分包标记,1允许分包,否则不允许
      pstRequest->SetMultiResponseFlag(1);
    
  • 响应处理。由于C++的api是异步模式,一般用户通过异步id将响应和请求一一对应,对于分包场景下的响应处理,需要通过响应中的标记(HaveMoreResPkgs 是否还有后续的包)来判断这个id的请求是否完成

    
      uint64_t asyncId = pstTcapRspRcved->GetAsynID();
      int32_t dwResult = pstTcapRspRcved->GetResult();
      // 响应失败
      if( 0 != dwResult)
      {
          //该异步id的任务失败了,可以直接做失败处理
          //比如从等待队列删除该异步id
          return;
      }
    
      //响应成功,读取该响应中的记录
      int32_t dwRecordCount = pstTcapRspRcved->GetRecordCount();//获取结果中记录的条数
      const TcaplusServiceRecord * pstTcapRecord = NULL;
      int32_t dwCount = 0;
      while(dwCount++ < dwRecordCount)
      {
          int32_t iRet = pstTcapRspRcved->FetchRecord(pstTcapRecord);
          if(0 != iRet || NULL == pstTcapRecord)
          {
              printf( "FetchRecord failed, iRet: %d \n", iRet);
              continue;
          }
    
          PLAYERONLINECNT stPLAYERONLINECNT;
          memset(&stPLAYERONLINECNT, 0, sizeof(stPLAYERONLINECNT));
          // 获得基于TDR描述的record数据
          iRet = pstTcapRecord->GetData(&stPLAYERONLINECNT, sizeof(stPLAYERONLINECNT));
          if(0 != iRet)
          {
              tlog_error(g_pstLogHandler, 0, 0, "GetData failed, iRet: %d .", iRet);
              return -4;
          }
          //业务处理这条记录stPLAYERONLINECNT
      }
    
      //后续包判断
      if (1 == pstTcapRspRcved->HaveMoreResPkgs())
      {
          //注意此时并不表示该异步ID的任务完成了!!!
          //触发了分包,还有后续的包,继续收包,等待下一个响应
      }
      else
      {
          //没有后续的包了,该异步ID的任务完成了
          //比如可以从等待队列中完成该ID的任务
      }
    

results matching ""

    No results matching ""