<commit_before>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// manager.cpp
//
// Identification: src/backend/catalog/manager.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <cassert>

#include "backend/catalog/manager.h"
#include "backend/storage/database.h"
#include "backend/storage/data_table.h"

namespace peloton {
namespace catalog {

Manager &Manager::GetInstance() {
  static Manager manager;
  return manager;
}

//===--------------------------------------------------------------------===//
// OBJECT MAP
//===--------------------------------------------------------------------===//

void Manager::SetTileGroup(const oid_t oid, storage::TileGroup *location) {
  {
    std::lock_guard<std::mutex> lock(locator_mutex);
    locator.insert(std::pair<oid_t, storage::TileGroup *>(oid, location));
  }
}

storage::TileGroup *Manager::GetTileGroup(const oid_t oid) {
  storage::TileGroup *location = nullptr;

  {
    std::lock_guard<std::mutex> lock(locator_mutex);
    location = locator.at(oid);
  }

  return location;
}

//used for logging test
void Manager::ClearTileGroup(){
  {
    std::lock_guard<std::mutex> lock(locator_mutex);
    locator.clear();
  }
}

//===--------------------------------------------------------------------===//
// DATABASE
//===--------------------------------------------------------------------===//

void Manager::AddDatabase(storage::Database *database) {
  {
    std::lock_guard<std::mutex> lock(catalog_mutex);
    databases.push_back(database);
  }
}

storage::Database *Manager::GetDatabaseWithOid(const oid_t database_oid) const {
  for (auto database : databases)
    if (database->GetOid() == database_oid) return database;

  return nullptr;
}

void Manager::DropDatabaseWithOid(const oid_t database_oid) {
  {
    std::lock_guard<std::mutex> lock(catalog_mutex);

    oid_t database_offset = 0;
    for (auto database : databases) {
      if (database->GetOid() == database_oid) {
        delete database;
        break;
      }
      database_offset++;
    }
    assert(database_offset < databases.size());

    // Drop the database
    databases.erase(databases.begin() + database_offset);
  }
}

storage::Database *Manager::GetDatabase(const oid_t database_offset) const {
  assert(database_offset < databases.size());
  auto database = databases.at(database_offset);
  return database;
}

oid_t Manager::GetDatabaseCount() const { return databases.size(); }

//===--------------------------------------------------------------------===//
// CONVENIENCE WRAPPERS
//===--------------------------------------------------------------------===//

storage::DataTable *Manager::GetTableWithOid(const oid_t database_oid,
                                             const oid_t table_oid) const {
  // Lookup DB
  auto database = GetDatabaseWithOid(database_oid);

  // Lookup table
  if (database != nullptr) {
    auto table = database->GetTableWithOid(table_oid);
    return table;
  }

  return nullptr;
}

storage::DataTable *Manager::GetTableWithName(
    const oid_t database_oid, const std::string table_name) const {
  // Lookup DB
  auto database = GetDatabaseWithOid(database_oid);

  // Lookup table
  if (database != nullptr) {
    auto table = database->GetTableWithName(table_name);
    return table;
  }

  return nullptr;
}

index::Index *Manager::GetIndexWithOid(const oid_t database_oid,
                                       const oid_t table_oid,
                                       const oid_t index_oid) const {
  // Lookup table
  auto table = GetTableWithOid(database_oid, table_oid);

  // Lookup index
  if (table != nullptr) {
    auto index = table->GetIndexWithOid(index_oid);
    return index;
  }

  return nullptr;
}

}  // End catalog namespace
}  // End peloton namespace
<commit_msg>Fix GetTileGroup bug<commit_after>//===----------------------------------------------------------------------===//
//
//                         PelotonDB
//
// manager.cpp
//
// Identification: src/backend/catalog/manager.cpp
//
// Copyright (c) 2015, Carnegie Mellon University Database Group
//
//===----------------------------------------------------------------------===//

#include <cassert>

#include "backend/catalog/manager.h"
#include "backend/storage/database.h"
#include "backend/storage/data_table.h"

namespace peloton {
namespace catalog {

Manager &Manager::GetInstance() {
  static Manager manager;
  return manager;
}

//===--------------------------------------------------------------------===//
// OBJECT MAP
//===--------------------------------------------------------------------===//

void Manager::SetTileGroup(const oid_t oid, storage::TileGroup *location) {
  {
    std::lock_guard<std::mutex> lock(locator_mutex);
    locator.insert(std::pair<oid_t, storage::TileGroup *>(oid, location));
  }
}

storage::TileGroup *Manager::GetTileGroup(const oid_t oid) {
  storage::TileGroup *location = nullptr;

  {
    std::lock_guard<std::mutex> lock(locator_mutex);
    if (locator.find(oid) != locator.end())
      location = locator.at(oid);
  }

  return location;
}

//used for logging test
void Manager::ClearTileGroup(){
  {
    std::lock_guard<std::mutex> lock(locator_mutex);
    locator.clear();
  }
}

//===--------------------------------------------------------------------===//
// DATABASE
//===--------------------------------------------------------------------===//

void Manager::AddDatabase(storage::Database *database) {
  {
    std::lock_guard<std::mutex> lock(catalog_mutex);
    databases.push_back(database);
  }
}

storage::Database *Manager::GetDatabaseWithOid(const oid_t database_oid) const {
  for (auto database : databases)
    if (database->GetOid() == database_oid) return database;

  return nullptr;
}

void Manager::DropDatabaseWithOid(const oid_t database_oid) {
  {
    std::lock_guard<std::mutex> lock(catalog_mutex);

    oid_t database_offset = 0;
    for (auto database : databases) {
      if (database->GetOid() == database_oid) {
        delete database;
        break;
      }
      database_offset++;
    }
    assert(database_offset < databases.size());

    // Drop the database
    databases.erase(databases.begin() + database_offset);
  }
}

storage::Database *Manager::GetDatabase(const oid_t database_offset) const {
  assert(database_offset < databases.size());
  auto database = databases.at(database_offset);
  return database;
}

oid_t Manager::GetDatabaseCount() const { return databases.size(); }

//===--------------------------------------------------------------------===//
// CONVENIENCE WRAPPERS
//===--------------------------------------------------------------------===//

storage::DataTable *Manager::GetTableWithOid(const oid_t database_oid,
                                             const oid_t table_oid) const {
  // Lookup DB
  auto database = GetDatabaseWithOid(database_oid);

  // Lookup table
  if (database != nullptr) {
    auto table = database->GetTableWithOid(table_oid);
    return table;
  }

  return nullptr;
}

storage::DataTable *Manager::GetTableWithName(
    const oid_t database_oid, const std::string table_name) const {
  // Lookup DB
  auto database = GetDatabaseWithOid(database_oid);

  // Lookup table
  if (database != nullptr) {
    auto table = database->GetTableWithName(table_name);
    return table;
  }

  return nullptr;
}

index::Index *Manager::GetIndexWithOid(const oid_t database_oid,
                                       const oid_t table_oid,
                                       const oid_t index_oid) const {
  // Lookup table
  auto table = GetTableWithOid(database_oid, table_oid);

  // Lookup index
  if (table != nullptr) {
    auto index = table->GetIndexWithOid(index_oid);
    return index;
  }

  return nullptr;
}

}  // End catalog namespace
}  // End peloton namespace
<|endoftext|>


<commit_before>// @(#)root/meta:$Id: TGWin32InterpreterProxy.cxx 38517 2011-03-18 20:20:16Z pcanal $
// Author: Valeriy Onuchin  15/11/2003

/*************************************************************************
 * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGWin32InterpreterProxy                                              //
//                                                                      //
// This class defines thread-safe interface to a command line           //
// interpreter (CINT).                                                  //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGWin32ProxyDefs.h"
#include "TGWin32InterpreterProxy.h"
#include "TROOT.h"
#include "TGWin32.h"

////////////////////////////////////////////////////////////////////////////////
//______________________________________________________________________________
TInterpreter *TGWin32InterpreterProxy::RealObject()
{
   // returns TCint object

   return gROOT->GetInterpreter();
}

RETURN_PROXY_OBJECT(Interpreter)
VOID_METHOD_ARG1(Interpreter,AddIncludePath,const char*,path,1)
RETURN_METHOD_ARG1(Interpreter,Int_t,AutoLoad,const char *,classname)
VOID_METHOD_ARG0(Interpreter,ClearFileBusy,1)
VOID_METHOD_ARG0(Interpreter,ClearStack,1)
VOID_METHOD_ARG0(Interpreter,EndOfLineAction,1)
VOID_METHOD_ARG0(Interpreter,EnableAutoLoading,1)
RETURN_METHOD_ARG0(Interpreter,Int_t,InitializeDictionaries)
// Does not support references:
//VOID_METHOD_ARG3(Interpreter,InspectMembers,TMemberInspector&, insp, void*, obj, const TClass*,cl,1)
void _NAME4_(p2,Interpreter,InspectMembers,insp)(void *in)
{
   struct tmp {
      TMemberInspector *par1; void *par2; const TClass *par3;
   };
   tmp *p = (tmp*)in;
   _NAME3_(TGWin32,Interpreter,Proxy)::RealObject()->method(p->par1,p->par2,p->par3);
}

void TGWin32InterpreterProxy::InspectMembers(TMemberInspector& insp, void* obj, const TClass* cl)
{
   DEBUG_PROFILE_PROXY_START(InspectMembers)
   struct tmp {
      TMemberInspector *par1; void *par2; const TClass *par3;
      tmp(type1 par1,void *par2,const TClass *par3):par1(&insp),par2(obj),par3(cl) {}
   };
   fParam = new tmp(&insp,obj,cl);
   fCallBack = &_NAME4_(p2,InspectMembers,TMemberInspector,insp);
   Bool_t batch = ForwardCallBack(1);
   par1 = ((tmp*)fParam)->par1;
   par2 = ((tmp*)fParam)->par2;
   par3 = ((tmp*)fParam)->par3;
   if (!batch) delete fParam;
   DEBUG_PROFILE_PROXY_STOP(InspectMembers)
}

RETURN_METHOD_ARG3(Interpreter,Int_t,GenerateDictionary,const char*,classes,const char*,headers,const char*,options);
RETURN_METHOD_ARG0(Interpreter,char*,GetPrompt)
RETURN_METHOD_ARG0(Interpreter,const char*,GetSharedLibs)
RETURN_METHOD_ARG0(Interpreter,const char*,GetIncludePath)
RETURN_METHOD_ARG2(Interpreter,Int_t,Load,const char*,filenam,Bool_t,system)
RETURN_METHOD_ARG1(Interpreter,Int_t,LoadLibraryMap,const char*,rootmapfile)
RETURN_METHOD_ARG0(Interpreter,Int_t,RescanLibraryMap)
RETURN_METHOD_ARG0(Interpreter,Int_t,ReloadAllSharedLibraryMaps)
RETURN_METHOD_ARG0(Interpreter,Int_t,UnloadAllSharedLibraryMaps)
RETURN_METHOD_ARG1(Interpreter,Int_t,UnloadLibraryMap,const char*,library)
VOID_METHOD_ARG2(Interpreter,LoadMacro,const char*,filename,TInterpreter::EErrorCode*,error,1)
RETURN_METHOD_ARG2(Interpreter,Long_t,ProcessLine,const char*,line,TInterpreter::EErrorCode*,error)
RETURN_METHOD_ARG2(Interpreter,Long_t,ProcessLineSynch,const char*,line,TInterpreter::EErrorCode*,error)
VOID_METHOD_ARG0(Interpreter,PrintIntro,1)
typedef const char* (*GetlineFunc_t)(const char* prompt);
typedef void (*HistaddFunc_t)(const char* line);
VOID_METHOD_ARG2(Interpreter,SetGetline,GetlineFunc_t, getlineFunc,\
                 HistaddFunc_t, histaddFunc, 1)
VOID_METHOD_ARG0(Interpreter,Reset,1)
VOID_METHOD_ARG0(Interpreter,ResetAll,1)
VOID_METHOD_ARG0(Interpreter,ResetGlobals,1)
VOID_METHOD_ARG1(Interpreter,ResetGlobalVar,void*,obj,1)
VOID_METHOD_ARG0(Interpreter,RewindDictionary,1)
RETURN_METHOD_ARG1(Interpreter,Int_t,DeleteGlobal,void*,obj)
VOID_METHOD_ARG0(Interpreter,SaveContext,1)
VOID_METHOD_ARG0(Interpreter,SaveGlobalsContext,1)
VOID_METHOD_ARG0_LOCK(Interpreter,UpdateListOfGlobals)
VOID_METHOD_ARG0_LOCK(Interpreter,UpdateListOfGlobalFunctions)
VOID_METHOD_ARG0_LOCK(Interpreter,UpdateListOfTypes)
VOID_METHOD_ARG2_LOCK(Interpreter,SetClassInfo,TClass*,cl,Bool_t,reload)
RETURN_METHOD_ARG2(Interpreter,Bool_t,CheckClassInfo,const char*,name,Bool_t,autoload)
RETURN_METHOD_ARG2(Interpreter,Long_t,Calc,const char*,line,TInterpreter::EErrorCode*,error)
VOID_METHOD_ARG1_LOCK(Interpreter,CreateListOfBaseClasses,TClass*,cl)
VOID_METHOD_ARG1_LOCK(Interpreter,CreateListOfDataMembers,TClass*,cl)
VOID_METHOD_ARG1_LOCK(Interpreter,CreateListOfMethods,TClass*,cl)
VOID_METHOD_ARG1_LOCK(Interpreter,CreateListOfMethodArgs,TFunction*,m)
VOID_METHOD_ARG1_LOCK(Interpreter,UpdateListOfMethods,TClass*,cl)
RETURN_METHOD_ARG3(Interpreter,TString,GetMangledName,TClass*,cl,const char*,method,const char*,params)
RETURN_METHOD_ARG3(Interpreter,TString,GetMangledNameWithPrototype,TClass*,cl,const char*,method,const char*,proto)
RETURN_METHOD_ARG3(Interpreter,void*,GetInterfaceMethod,TClass*,cl,const char*,method,const char*,params)
RETURN_METHOD_ARG3(Interpreter,void*,GetInterfaceMethodWithPrototype,TClass*,cl,const char*,method,const char*,proto)
RETURN_METHOD_ARG1(Interpreter,const char*,GetClassSharedLibs,const char*,s)
RETURN_METHOD_ARG1(Interpreter,const char*,GetSharedLibDeps,const char*,s)
RETURN_METHOD_ARG2(Interpreter,const char*,GetInterpreterTypeName,const char*,s,Bool_t,full)
VOID_METHOD_ARG3(Interpreter,Execute,const char*,function,const char*,params,int*,error,1)
VOID_METHOD_ARG5(Interpreter,Execute,TObject*,obj,TClass*,cl,const char*,method,const char*,params,int*,error,1)
VOID_METHOD_ARG5(Interpreter,Execute,TObject*,object,TClass*,cl,TMethod*,method,TObjArray*,params,int*,error,1)
RETURN_METHOD_ARG2(Interpreter,Long_t,ExecuteMacro,const char*,filename,TInterpreter::EErrorCode*,error)
RETURN_METHOD_ARG1(Interpreter,Bool_t,SetErrorMessages,Bool_t,enable)
VOID_METHOD_ARG1(Interpreter,SetProcessLineLock,Bool_t,lock,1)
RETURN_METHOD_ARG1(Interpreter,const char*,TypeName,const char*,s)
//Bool_t TGWin32InterpreterProxy::CheckClassInfo(const char* name) { return RealObject()->CheckClassInfo(name); }
<commit_msg>Try harder to fix windows compilation errors (the existing macro do not support reference param<commit_after>// @(#)root/meta:$Id: TGWin32InterpreterProxy.cxx 38517 2011-03-18 20:20:16Z pcanal $
// Author: Valeriy Onuchin  15/11/2003

/*************************************************************************
 * Copyright (C) 1995-2001, Rene Brun and Fons Rademakers.               *
 * All rights reserved.                                                  *
 *                                                                       *
 * For the licensing terms see $ROOTSYS/LICENSE.                         *
 * For the list of contributors see $ROOTSYS/README/CREDITS.             *
 *************************************************************************/

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// TGWin32InterpreterProxy                                              //
//                                                                      //
// This class defines thread-safe interface to a command line           //
// interpreter (CINT).                                                  //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include "TGWin32ProxyDefs.h"
#include "TGWin32InterpreterProxy.h"
#include "TROOT.h"
#include "TGWin32.h"

////////////////////////////////////////////////////////////////////////////////
//______________________________________________________________________________
TInterpreter *TGWin32InterpreterProxy::RealObject()
{
   // returns TCint object

   return gROOT->GetInterpreter();
}

RETURN_PROXY_OBJECT(Interpreter)
VOID_METHOD_ARG1(Interpreter,AddIncludePath,const char*,path,1)
RETURN_METHOD_ARG1(Interpreter,Int_t,AutoLoad,const char *,classname)
VOID_METHOD_ARG0(Interpreter,ClearFileBusy,1)
VOID_METHOD_ARG0(Interpreter,ClearStack,1)
VOID_METHOD_ARG0(Interpreter,EndOfLineAction,1)
VOID_METHOD_ARG0(Interpreter,EnableAutoLoading,1)
RETURN_METHOD_ARG0(Interpreter,Int_t,InitializeDictionaries)
// Does not support references:
//VOID_METHOD_ARG3(Interpreter,InspectMembers,TMemberInspector&, insp, void*, obj, const TClass*,cl,1)
void _NAME4_(p2,Interpreter,InspectMembers,insp)(void *in)
{
   struct tmp {
      TMemberInspector *par1; void *par2; const TClass *par3;
   };
   tmp *p = (tmp*)in;
   _NAME3_(TGWin32,Interpreter,Proxy)::RealObject()->InspectMembers(p->par1,p->par2,p->par3);
}

void TGWin32InterpreterProxy::InspectMembers(TMemberInspector& insp, void* obj, const TClass* cl)
{
   DEBUG_PROFILE_PROXY_START(InspectMembers)
   struct tmp {
      TMemberInspector *par1; void *par2; const TClass *par3;
      tmp(TMemberInspector * par1,void *par2,const TClass *par3):par1(&insp),par2(obj),par3(cl) {}
   };
   fParam = new tmp(&insp,obj,cl);
   fCallBack = &_NAME4_(p2,InspectMembers,TMemberInspector,insp);
   Bool_t batch = ForwardCallBack(1);
   //   insp = ((tmp*)fParam)->par1;
   obj = ((tmp*)fParam)->par2;
   cl = ((tmp*)fParam)->par3;
   if (!batch) delete fParam;
   DEBUG_PROFILE_PROXY_STOP(InspectMembers)
}

RETURN_METHOD_ARG3(Interpreter,Int_t,GenerateDictionary,const char*,classes,const char*,headers,const char*,options);
RETURN_METHOD_ARG0(Interpreter,char*,GetPrompt)
RETURN_METHOD_ARG0(Interpreter,const char*,GetSharedLibs)
RETURN_METHOD_ARG0(Interpreter,const char*,GetIncludePath)
RETURN_METHOD_ARG2(Interpreter,Int_t,Load,const char*,filenam,Bool_t,system)
RETURN_METHOD_ARG1(Interpreter,Int_t,LoadLibraryMap,const char*,rootmapfile)
RETURN_METHOD_ARG0(Interpreter,Int_t,RescanLibraryMap)
RETURN_METHOD_ARG0(Interpreter,Int_t,ReloadAllSharedLibraryMaps)
RETURN_METHOD_ARG0(Interpreter,Int_t,UnloadAllSharedLibraryMaps)
RETURN_METHOD_ARG1(Interpreter,Int_t,UnloadLibraryMap,const char*,library)
VOID_METHOD_ARG2(Interpreter,LoadMacro,const char*,filename,TInterpreter::EErrorCode*,error,1)
RETURN_METHOD_ARG2(Interpreter,Long_t,ProcessLine,const char*,line,TInterpreter::EErrorCode*,error)
RETURN_METHOD_ARG2(Interpreter,Long_t,ProcessLineSynch,const char*,line,TInterpreter::EErrorCode*,error)
VOID_METHOD_ARG0(Interpreter,PrintIntro,1)
typedef const char* (*GetlineFunc_t)(const char* prompt);
typedef void (*HistaddFunc_t)(const char* line);
VOID_METHOD_ARG2(Interpreter,SetGetline,GetlineFunc_t, getlineFunc,\
                 HistaddFunc_t, histaddFunc, 1)
VOID_METHOD_ARG0(Interpreter,Reset,1)
VOID_METHOD_ARG0(Interpreter,ResetAll,1)
VOID_METHOD_ARG0(Interpreter,ResetGlobals,1)
VOID_METHOD_ARG1(Interpreter,ResetGlobalVar,void*,obj,1)
VOID_METHOD_ARG0(Interpreter,RewindDictionary,1)
RETURN_METHOD_ARG1(Interpreter,Int_t,DeleteGlobal,void*,obj)
VOID_METHOD_ARG0(Interpreter,SaveContext,1)
VOID_METHOD_ARG0(Interpreter,SaveGlobalsContext,1)
VOID_METHOD_ARG0_LOCK(Interpreter,UpdateListOfGlobals)
VOID_METHOD_ARG0_LOCK(Interpreter,UpdateListOfGlobalFunctions)
VOID_METHOD_ARG0_LOCK(Interpreter,UpdateListOfTypes)
VOID_METHOD_ARG2_LOCK(Interpreter,SetClassInfo,TClass*,cl,Bool_t,reload)
RETURN_METHOD_ARG2(Interpreter,Bool_t,CheckClassInfo,const char*,name,Bool_t,autoload)
RETURN_METHOD_ARG2(Interpreter,Long_t,Calc,const char*,line,TInterpreter::EErrorCode*,error)
VOID_METHOD_ARG1_LOCK(Interpreter,CreateListOfBaseClasses,TClass*,cl)
VOID_METHOD_ARG1_LOCK(Interpreter,CreateListOfDataMembers,TClass*,cl)
VOID_METHOD_ARG1_LOCK(Interpreter,CreateListOfMethods,TClass*,cl)
VOID_METHOD_ARG1_LOCK(Interpreter,CreateListOfMethodArgs,TFunction*,m)
VOID_METHOD_ARG1_LOCK(Interpreter,UpdateListOfMethods,TClass*,cl)
RETURN_METHOD_ARG3(Interpreter,TString,GetMangledName,TClass*,cl,const char*,method,const char*,params)
RETURN_METHOD_ARG3(Interpreter,TString,GetMangledNameWithPrototype,TClass*,cl,const char*,method,const char*,proto)
RETURN_METHOD_ARG3(Interpreter,void*,GetInterfaceMethod,TClass*,cl,const char*,method,const char*,params)
RETURN_METHOD_ARG3(Interpreter,void*,GetInterfaceMethodWithPrototype,TClass*,cl,const char*,method,const char*,proto)
RETURN_METHOD_ARG1(Interpreter,const char*,GetClassSharedLibs,const char*,s)
RETURN_METHOD_ARG1(Interpreter,const char*,GetSharedLibDeps,const char*,s)
RETURN_METHOD_ARG2(Interpreter,const char*,GetInterpreterTypeName,const char*,s,Bool_t,full)
VOID_METHOD_ARG3(Interpreter,Execute,const char*,function,const char*,params,int*,error,1)
VOID_METHOD_ARG5(Interpreter,Execute,TObject*,obj,TClass*,cl,const char*,method,const char*,params,int*,error,1)
VOID_METHOD_ARG5(Interpreter,Execute,TObject*,object,TClass*,cl,TMethod*,method,TObjArray*,params,int*,error,1)
RETURN_METHOD_ARG2(Interpreter,Long_t,ExecuteMacro,const char*,filename,TInterpreter::EErrorCode*,error)
RETURN_METHOD_ARG1(Interpreter,Bool_t,SetErrorMessages,Bool_t,enable)
VOID_METHOD_ARG1(Interpreter,SetProcessLineLock,Bool_t,lock,1)
RETURN_METHOD_ARG1(Interpreter,const char*,TypeName,const char*,s)
//Bool_t TGWin32InterpreterProxy::CheckClassInfo(const char* name) { return RealObject()->CheckClassInfo(name); }
<|endoftext|>


<commit_before>/*
 * Executor.cpp
 *
 *  Created on: Oct 20, 2015
 *      Author: Péter Fankhauser
 *   Institute: ETH Zurich, Autonomous Systems Lab
 */

#include "free_gait_core/executor/Executor.hpp"
#include "free_gait_core/leg_motion/JointTrajectory.hpp"

namespace free_gait {

Executor::Executor(std::shared_ptr<StepCompleter> completer,
                   std::shared_ptr<AdapterBase> adapter,
                   std::shared_ptr<State> state)
    : completer_(completer),
      adapter_(adapter),
      state_(state),
      isInitialized_(false)
{
}

Executor::~Executor()
{
}

bool Executor::initialize()
{
  Lock lock(mutex_);
  state_->initialize(adapter_->getLimbs(), adapter_->getBranches());
  reset();
  return isInitialized_ = true;
}

bool Executor::isInitialized() const
{
  return isInitialized_;
}

Executor::Mutex& Executor::getMutex()
{
  return mutex_;
}

bool Executor::advance(double dt)
{
  Lock lock(mutex_);

  if (!isInitialized_) return false;
  updateStateWithMeasurements();
  bool executionStatus = adapter_->isExecutionOk();

  if (executionStatus) {
    if (!state_->getRobotExecutionStatus()) std::cout << "Continuing with free gait execution." << std::endl;
    state_->setRobotExecutionStatus(true);
  } else {
    if (state_->getRobotExecutionStatus()) std::cout << "Robot status is not OK, not continuing with free gait execution." << std::endl;
    state_->setRobotExecutionStatus(false);
    return true;
  }

  bool hasSwitchedStep;
  if (!queue_.advance(dt, hasSwitchedStep)) return false;

  while (hasSwitchedStep) {

    if (!queue_.getCurrentStep().requiresMultiThreading()) {
      if (!completeCurrentStep()) return false;
      if (!queue_.advance(dt, hasSwitchedStep)) return false; // Advance again after completion.
    } else {
      std::thread thread(&Executor::completeCurrentStep, this, true);
      thread.detach();
      hasSwitchedStep = false;
    }
  }

  if (!writeIgnoreContact()) return false;
  if (!writeIgnoreForPoseAdaptation()) return false;
  if (!writeSupportLegs()) return false;
  if (!writeSurfaceNormals()) return false;
  if (!writeLegMotion()) return false;
  if (!writeTorsoMotion()) return false;
  if (!adapter_->updateExtras(queue_, *state_)) return false;
//  std::cout << *state_ << std::endl;

  return true;
}

bool Executor::completeCurrentStep(bool multiThreaded)
{
  robotUtils::HighResolutionClockTimer timer("Executor::completeCurrentStep");
  timer.pinTime();

  // TODO: Add mutexes on state and queue?
  bool completionSuccessful;
  if (multiThreaded) {
    const State state(*state_);
    completionSuccessful = completer_->complete(state, queue_, queue_.getCurrentStep());
  } else {
    completionSuccessful = completer_->complete(*state_, queue_, queue_.getCurrentStep());
  }

  if (!completionSuccessful) {
    std::cerr << "Executor::advance: Could not complete step." << std::endl;
    return false;
  }

  timer.splitTime();
  std::cout << timer << std::endl;
  std::cout << "Switched step to:" << std::endl;
  std::cout << queue_.getCurrentStep() << std::endl;
  return true;
}

void Executor::reset()
{
  Lock lock(mutex_);
  queue_.clear();
  initializeStateWithRobot();
}

const StepQueue& Executor::getQueue() const
{
  return queue_;
}

StepQueue& Executor::getQueue()
{
  return queue_;
}

const State& Executor::getState() const
{
  return *state_;
}

const AdapterBase& Executor::getAdapter() const
{
  return *adapter_;
}

bool Executor::initializeStateWithRobot()
{
  for (const auto& limb : adapter_->getLimbs()) {
    state_->setSupportLeg(limb, adapter_->isLegGrounded(limb));
    state_->setIgnoreContact(limb, !adapter_->isLegGrounded(limb));
    state_->setIgnoreForPoseAdaptation(limb, !adapter_->isLegGrounded(limb));
    state_->removeSurfaceNormal(limb);
  }

  if (state_->getNumberOfSupportLegs() > 0) {
    state_->setControlSetup(BranchEnum::BASE, adapter_->getControlSetup(BranchEnum::BASE));
  } else {
    state_->setEmptyControlSetup(BranchEnum::BASE);
  }

  for (const auto& limb : adapter_->getLimbs()) {
    if (state_->isSupportLeg(limb)) {
      state_->setEmptyControlSetup(limb);
    } else {
      state_->setControlSetup(limb, adapter_->getControlSetup(limb));
    }
  }

  state_->setAllJointPositions(adapter_->getAllJointPositions());
  state_->setAllJointVelocities(adapter_->getAllJointVelocities());
//  state_->setAllJointAccelerations(adapter_->getAllJointAccelerations()); // TODO
  state_->setAllJointEfforts(adapter_->getAllJointEfforts());
  state_->setPositionWorldToBaseInWorldFrame(adapter_->getPositionWorldToBaseInWorldFrame());
  state_->setOrientationWorldToBase(adapter_->getOrientationWorldToBase());

  for (const auto& limb : adapter_->getLimbs()) {
    state_->setSupportLeg(limb, adapter_->isLegGrounded(limb));
    state_->setIgnoreContact(limb, !adapter_->isLegGrounded(limb));
  }

  state_->setRobotExecutionStatus(true);

  return true;
}

bool Executor::updateStateWithMeasurements()
{
  for (const auto& limb : adapter_->getLimbs()) {
    const auto& controlSetup = state_->getControlSetup(limb);
    if (!controlSetup.at(ControlLevel::Position)) {
      state_->setJointPositions(limb, adapter_->getJointPositions(limb));
    }
    if (!controlSetup.at(ControlLevel::Velocity)) {
      state_->setJointVelocities(limb, adapter_->getJointVelocities(limb));
    }
    if (!controlSetup.at(ControlLevel::Acceleration)) {
//      state_->setJointAccelerations(limb, adapter_->getJointAccelerations(limb));
    }
    if (!controlSetup.at(ControlLevel::Effort)) {
      state_->setJointEfforts(limb, adapter_->getJointEfforts(limb));
    }
  }

  const auto& controlSetup = state_->getControlSetup(BranchEnum::BASE);
  if (!controlSetup.at(ControlLevel::Position)) {
    state_->setPositionWorldToBaseInWorldFrame(adapter_->getPositionWorldToBaseInWorldFrame());
    state_->setOrientationWorldToBase(adapter_->getOrientationWorldToBase());
  }

  state_->setAllJointVelocities(adapter_->getAllJointVelocities());
  // TODO Copy also acceleraitons and torques.
//    state.setLinearVelocityBaseInWorldFrame(torso_->getMeasuredState().getLinearVelocityBaseInBaseFrame());
//    state.setAngularVelocityBaseInBaseFrame(torso_->getMeasuredState().getAngularVelocityBaseInBaseFrame());
  return true;
}

bool Executor::writeIgnoreContact()
{
  if (!queue_.active()) return true;
  const Step& step = queue_.getCurrentStep();
  for (const auto& limb : adapter_->getLimbs()) {
    if (step.hasLegMotion(limb)) {
      bool ignoreContact = step.getLegMotion(limb).isIgnoreContact();
      state_->setIgnoreContact(limb, ignoreContact);
    }
  }
  return true;
}

bool Executor::writeIgnoreForPoseAdaptation()
{
  if (!queue_.active()) return true;
  const Step& step = queue_.getCurrentStep();
  for (const auto& limb : adapter_->getLimbs()) {
    if (step.hasLegMotion(limb)) {
      bool ignoreForPoseAdaptation = step.getLegMotion(limb).isIgnoreForPoseAdaptation();
      state_->setIgnoreForPoseAdaptation(limb, ignoreForPoseAdaptation);
    }
  }
  return true;
}

bool Executor::writeSupportLegs()
{
  if (!queue_.active()) {
    for (const auto& limb : adapter_->getLimbs()) {
      state_->setSupportLeg(limb, !state_->isIgnoreContact(limb));
    }
    return true;
  }

  const Step& step = queue_.getCurrentStep();
  for (const auto& limb : adapter_->getLimbs()) {
    if (step.hasLegMotion(limb) || state_->isIgnoreContact(limb)) {
      state_->setSupportLeg(limb, false);
    } else {
      state_->setSupportLeg(limb, true);
    }
  }
  return true;
}

bool Executor::writeSurfaceNormals()
{
  if (!queue_.active()) return true;
  const Step& step = queue_.getCurrentStep();
  for (const auto& limb : adapter_->getLimbs()) {
    if (step.hasLegMotion(limb)) {
      if (step.getLegMotion(limb).hasSurfaceNormal()) {
        state_->setSurfaceNormal(limb, step.getLegMotion(limb).getSurfaceNormal());
      } else {
        state_->removeSurfaceNormal(limb);
      }
    }
  }
  return true;
}

bool Executor::writeLegMotion()
{
  for (const auto& limb : adapter_->getLimbs()) {
    if (state_->isSupportLeg(limb)) state_->setEmptyControlSetup(limb);
  }
  if (!queue_.active()) return true;

  const auto& step = queue_.getCurrentStep();
  if (!step.hasLegMotion()) return true;

  double time = queue_.getCurrentStep().getTime();
  for (const auto& limb : adapter_->getLimbs()) {
    if (!step.hasLegMotion(limb)) continue;
    auto const& legMotion = step.getLegMotion(limb);
    ControlSetup controlSetup = legMotion.getControlSetup();
    state_->setControlSetup(limb, controlSetup);

    switch (legMotion.getTrajectoryType()) {

      case LegMotionBase::TrajectoryType::EndEffector:
      {
        const auto& endEffectorMotion = dynamic_cast<const EndEffectorMotionBase&>(legMotion);
        if (controlSetup[ControlLevel::Position]) {
          // TODO Add frame handling.
          Position positionInWorldFrame(endEffectorMotion.evaluatePosition(time));
          // TODO adapter_->getOrientationWorldToBase() is nicer when the robot slips, but leads to problems at lift-off.
          Position positionInBaseFrame(adapter_->getOrientationWorldToBase().rotate(positionInWorldFrame - adapter_->getPositionWorldToBaseInWorldFrame()));
//          Position positionInBaseFrame(state_->getOrientationWorldToBase().rotate(positionInWorldFrame - adapter_->getPositionWorldToBaseInWorldFrame()));
          JointPositions jointPositions;
          adapter_->getLimbJointPositionsFromPositionBaseToFootInBaseFrame(positionInBaseFrame, limb, jointPositions);
          state_->setJointPositions(limb, jointPositions);
        }
        break;
      }

      case LegMotionBase::TrajectoryType::Joints:
      {
        const auto& jointMotion = dynamic_cast<const JointMotionBase&>(legMotion);
        if (controlSetup[ControlLevel::Position]) state_->setJointPositions(limb, jointMotion.evaluatePosition(time));
//        if (controlSetup[ControlLevel::Velocity]) state_->setJointVelocities(limb, jointMotion.evaluateVelocity(time));
//        if (controlSetup[ControlLevel::Acceleration]) state_->setJointAcceleration(limb, jointMotion.evaluateAcceleration(time));
        if (controlSetup[ControlLevel::Effort]) state_->setJointEfforts(limb, jointMotion.evaluateEffort(time));
        break;
      }

      default:
        throw std::runtime_error("Executor::writeLegMotion() could not write leg motion of this type.");
        break;
    }
  }

  return true;
}

bool Executor::writeTorsoMotion()
{
  if (state_->getNumberOfSupportLegs() == 0) state_->setEmptyControlSetup(BranchEnum::BASE);
  if (!queue_.active()) return true;

  if (!queue_.getCurrentStep().hasBaseMotion()) return true;
  double time = queue_.getCurrentStep().getTime();
  // TODO Add frame handling.
  const auto& baseMotion = queue_.getCurrentStep().getBaseMotion();
  ControlSetup controlSetup = baseMotion.getControlSetup();
  state_->setControlSetup(BranchEnum::BASE, controlSetup);
  if (controlSetup[ControlLevel::Position]) {
    Pose pose = baseMotion.evaluatePose(time);
    state_->setPositionWorldToBaseInWorldFrame(pose.getPosition());
    state_->setOrientationWorldToBase(pose.getRotation());
  }
  if (controlSetup[ControlLevel::Velocity]) {
    Twist twist = baseMotion.evaluateTwist(time);
    state_->setLinearVelocityBaseInWorldFrame(twist.getTranslationalVelocity());
    state_->setAngularVelocityBaseInBaseFrame(twist.getRotationalVelocity());
  }
  // TODO Set more states.
  return true;
}

} /* namespace free_gait */
<commit_msg>Added better mutex protection of the free gait state.<commit_after>/*
 * Executor.cpp
 *
 *  Created on: Oct 20, 2015
 *      Author: Péter Fankhauser
 *   Institute: ETH Zurich, Autonomous Systems Lab
 */

#include "free_gait_core/executor/Executor.hpp"
#include "free_gait_core/leg_motion/JointTrajectory.hpp"

namespace free_gait {

Executor::Executor(std::shared_ptr<StepCompleter> completer,
                   std::shared_ptr<AdapterBase> adapter,
                   std::shared_ptr<State> state)
    : completer_(completer),
      adapter_(adapter),
      state_(state),
      isInitialized_(false)
{
}

Executor::~Executor()
{
}

bool Executor::initialize()
{
  Lock lock(mutex_);
  state_->initialize(adapter_->getLimbs(), adapter_->getBranches());
  reset();
  return isInitialized_ = true;
}

bool Executor::isInitialized() const
{
  return isInitialized_;
}

Executor::Mutex& Executor::getMutex()
{
  return mutex_;
}

bool Executor::advance(double dt)
{
  Lock lock(mutex_);

  if (!isInitialized_) return false;
  updateStateWithMeasurements();
  bool executionStatus = adapter_->isExecutionOk();

  if (executionStatus) {
    if (!state_->getRobotExecutionStatus()) std::cout << "Continuing with free gait execution." << std::endl;
    state_->setRobotExecutionStatus(true);
  } else {
    if (state_->getRobotExecutionStatus()) std::cout << "Robot status is not OK, not continuing with free gait execution." << std::endl;
    state_->setRobotExecutionStatus(false);
    return true;
  }

  bool hasSwitchedStep;
  if (!queue_.advance(dt, hasSwitchedStep)) return false;

  while (hasSwitchedStep) {

    if (!queue_.getCurrentStep().requiresMultiThreading()) {
      if (!completeCurrentStep()) return false;
      if (!queue_.advance(dt, hasSwitchedStep)) return false; // Advance again after completion.
    } else {
      std::thread thread(&Executor::completeCurrentStep, this, true);
      thread.detach();
      hasSwitchedStep = false;
    }
  }

  if (!writeIgnoreContact()) return false;
  if (!writeIgnoreForPoseAdaptation()) return false;
  if (!writeSupportLegs()) return false;
  if (!writeSurfaceNormals()) return false;
  if (!writeLegMotion()) return false;
  if (!writeTorsoMotion()) return false;
  if (!adapter_->updateExtras(queue_, *state_)) return false;
//  std::cout << *state_ << std::endl;

  return true;
}

bool Executor::completeCurrentStep(bool multiThreaded)
{
  robotUtils::HighResolutionClockTimer timer("Executor::completeCurrentStep");
  timer.pinTime();

  // TODO: Add mutexes on state and queue?
  bool completionSuccessful;
  if (multiThreaded) {
    Lock lock(mutex_);
    const State state(*state_);
    lock.unlock();
    completionSuccessful = completer_->complete(state, queue_, queue_.getCurrentStep());
  } else {
    completionSuccessful = completer_->complete(*state_, queue_, queue_.getCurrentStep());
  }

  if (!completionSuccessful) {
    std::cerr << "Executor::advance: Could not complete step." << std::endl;
    return false;
  }

  timer.splitTime();
  std::cout << timer << std::endl;
  std::cout << "Switched step to:" << std::endl;
  std::cout << queue_.getCurrentStep() << std::endl;
  return true;
}

void Executor::reset()
{
  Lock lock(mutex_);
  queue_.clear();
  initializeStateWithRobot();
}

const StepQueue& Executor::getQueue() const
{
  return queue_;
}

StepQueue& Executor::getQueue()
{
  return queue_;
}

const State& Executor::getState() const
{
  return *state_;
}

const AdapterBase& Executor::getAdapter() const
{
  return *adapter_;
}

bool Executor::initializeStateWithRobot()
{
  for (const auto& limb : adapter_->getLimbs()) {
    state_->setSupportLeg(limb, adapter_->isLegGrounded(limb));
    state_->setIgnoreContact(limb, !adapter_->isLegGrounded(limb));
    state_->setIgnoreForPoseAdaptation(limb, !adapter_->isLegGrounded(limb));
    state_->removeSurfaceNormal(limb);
  }

  if (state_->getNumberOfSupportLegs() > 0) {
    state_->setControlSetup(BranchEnum::BASE, adapter_->getControlSetup(BranchEnum::BASE));
  } else {
    state_->setEmptyControlSetup(BranchEnum::BASE);
  }

  for (const auto& limb : adapter_->getLimbs()) {
    if (state_->isSupportLeg(limb)) {
      state_->setEmptyControlSetup(limb);
    } else {
      state_->setControlSetup(limb, adapter_->getControlSetup(limb));
    }
  }

  state_->setAllJointPositions(adapter_->getAllJointPositions());
  state_->setAllJointVelocities(adapter_->getAllJointVelocities());
//  state_->setAllJointAccelerations(adapter_->getAllJointAccelerations()); // TODO
  state_->setAllJointEfforts(adapter_->getAllJointEfforts());
  state_->setPositionWorldToBaseInWorldFrame(adapter_->getPositionWorldToBaseInWorldFrame());
  state_->setOrientationWorldToBase(adapter_->getOrientationWorldToBase());

  for (const auto& limb : adapter_->getLimbs()) {
    state_->setSupportLeg(limb, adapter_->isLegGrounded(limb));
    state_->setIgnoreContact(limb, !adapter_->isLegGrounded(limb));
  }

  state_->setRobotExecutionStatus(true);

  return true;
}

bool Executor::updateStateWithMeasurements()
{
  for (const auto& limb : adapter_->getLimbs()) {
    const auto& controlSetup = state_->getControlSetup(limb);
    if (!controlSetup.at(ControlLevel::Position)) {
      state_->setJointPositions(limb, adapter_->getJointPositions(limb));
    }
    if (!controlSetup.at(ControlLevel::Velocity)) {
      state_->setJointVelocities(limb, adapter_->getJointVelocities(limb));
    }
    if (!controlSetup.at(ControlLevel::Acceleration)) {
//      state_->setJointAccelerations(limb, adapter_->getJointAccelerations(limb));
    }
    if (!controlSetup.at(ControlLevel::Effort)) {
      state_->setJointEfforts(limb, adapter_->getJointEfforts(limb));
    }
  }

  const auto& controlSetup = state_->getControlSetup(BranchEnum::BASE);
  if (!controlSetup.at(ControlLevel::Position)) {
    state_->setPositionWorldToBaseInWorldFrame(adapter_->getPositionWorldToBaseInWorldFrame());
    state_->setOrientationWorldToBase(adapter_->getOrientationWorldToBase());
  }

  state_->setAllJointVelocities(adapter_->getAllJointVelocities());
  // TODO Copy also acceleraitons and torques.
//    state.setLinearVelocityBaseInWorldFrame(torso_->getMeasuredState().getLinearVelocityBaseInBaseFrame());
//    state.setAngularVelocityBaseInBaseFrame(torso_->getMeasuredState().getAngularVelocityBaseInBaseFrame());
  return true;
}

bool Executor::writeIgnoreContact()
{
  if (!queue_.active()) return true;
  const Step& step = queue_.getCurrentStep();
  for (const auto& limb : adapter_->getLimbs()) {
    if (step.hasLegMotion(limb)) {
      bool ignoreContact = step.getLegMotion(limb).isIgnoreContact();
      state_->setIgnoreContact(limb, ignoreContact);
    }
  }
  return true;
}

bool Executor::writeIgnoreForPoseAdaptation()
{
  if (!queue_.active()) return true;
  const Step& step = queue_.getCurrentStep();
  for (const auto& limb : adapter_->getLimbs()) {
    if (step.hasLegMotion(limb)) {
      bool ignoreForPoseAdaptation = step.getLegMotion(limb).isIgnoreForPoseAdaptation();
      state_->setIgnoreForPoseAdaptation(limb, ignoreForPoseAdaptation);
    }
  }
  return true;
}

bool Executor::writeSupportLegs()
{
  if (!queue_.active()) {
    for (const auto& limb : adapter_->getLimbs()) {
      state_->setSupportLeg(limb, !state_->isIgnoreContact(limb));
    }
    return true;
  }

  const Step& step = queue_.getCurrentStep();
  for (const auto& limb : adapter_->getLimbs()) {
    if (step.hasLegMotion(limb) || state_->isIgnoreContact(limb)) {
      state_->setSupportLeg(limb, false);
    } else {
      state_->setSupportLeg(limb, true);
    }
  }
  return true;
}

bool Executor::writeSurfaceNormals()
{
  if (!queue_.active()) return true;
  const Step& step = queue_.getCurrentStep();
  for (const auto& limb : adapter_->getLimbs()) {
    if (step.hasLegMotion(limb)) {
      if (step.getLegMotion(limb).hasSurfaceNormal()) {
        state_->setSurfaceNormal(limb, step.getLegMotion(limb).getSurfaceNormal());
      } else {
        state_->removeSurfaceNormal(limb);
      }
    }
  }
  return true;
}

bool Executor::writeLegMotion()
{
  for (const auto& limb : adapter_->getLimbs()) {
    if (state_->isSupportLeg(limb)) state_->setEmptyControlSetup(limb);
  }
  if (!queue_.active()) return true;

  const auto& step = queue_.getCurrentStep();
  if (!step.hasLegMotion()) return true;

  double time = queue_.getCurrentStep().getTime();
  for (const auto& limb : adapter_->getLimbs()) {
    if (!step.hasLegMotion(limb)) continue;
    auto const& legMotion = step.getLegMotion(limb);
    ControlSetup controlSetup = legMotion.getControlSetup();
    state_->setControlSetup(limb, controlSetup);

    switch (legMotion.getTrajectoryType()) {

      case LegMotionBase::TrajectoryType::EndEffector:
      {
        const auto& endEffectorMotion = dynamic_cast<const EndEffectorMotionBase&>(legMotion);
        if (controlSetup[ControlLevel::Position]) {
          // TODO Add frame handling.
          Position positionInWorldFrame(endEffectorMotion.evaluatePosition(time));
          // TODO adapter_->getOrientationWorldToBase() is nicer when the robot slips, but leads to problems at lift-off.
          Position positionInBaseFrame(adapter_->getOrientationWorldToBase().rotate(positionInWorldFrame - adapter_->getPositionWorldToBaseInWorldFrame()));
//          Position positionInBaseFrame(state_->getOrientationWorldToBase().rotate(positionInWorldFrame - adapter_->getPositionWorldToBaseInWorldFrame()));
          JointPositions jointPositions;
          adapter_->getLimbJointPositionsFromPositionBaseToFootInBaseFrame(positionInBaseFrame, limb, jointPositions);
          state_->setJointPositions(limb, jointPositions);
        }
        break;
      }

      case LegMotionBase::TrajectoryType::Joints:
      {
        const auto& jointMotion = dynamic_cast<const JointMotionBase&>(legMotion);
        if (controlSetup[ControlLevel::Position]) state_->setJointPositions(limb, jointMotion.evaluatePosition(time));
//        if (controlSetup[ControlLevel::Velocity]) state_->setJointVelocities(limb, jointMotion.evaluateVelocity(time));
//        if (controlSetup[ControlLevel::Acceleration]) state_->setJointAcceleration(limb, jointMotion.evaluateAcceleration(time));
        if (controlSetup[ControlLevel::Effort]) state_->setJointEfforts(limb, jointMotion.evaluateEffort(time));
        break;
      }

      default:
        throw std::runtime_error("Executor::writeLegMotion() could not write leg motion of this type.");
        break;
    }
  }

  return true;
}

bool Executor::writeTorsoMotion()
{
  if (state_->getNumberOfSupportLegs() == 0) state_->setEmptyControlSetup(BranchEnum::BASE);
  if (!queue_.active()) return true;

  if (!queue_.getCurrentStep().hasBaseMotion()) return true;
  double time = queue_.getCurrentStep().getTime();
  // TODO Add frame handling.
  const auto& baseMotion = queue_.getCurrentStep().getBaseMotion();
  ControlSetup controlSetup = baseMotion.getControlSetup();
  state_->setControlSetup(BranchEnum::BASE, controlSetup);
  if (controlSetup[ControlLevel::Position]) {
    Pose pose = baseMotion.evaluatePose(time);
    state_->setPositionWorldToBaseInWorldFrame(pose.getPosition());
    state_->setOrientationWorldToBase(pose.getRotation());
  }
  if (controlSetup[ControlLevel::Velocity]) {
    Twist twist = baseMotion.evaluateTwist(time);
    state_->setLinearVelocityBaseInWorldFrame(twist.getTranslationalVelocity());
    state_->setAngularVelocityBaseInBaseFrame(twist.getRotationalVelocity());
  }
  // TODO Set more states.
  return true;
}

} /* namespace free_gait */
<|endoftext|>


<commit_before>//===--- CommentDumper.cpp - Dumping implementation for Comment ASTs ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/CommentVisitor.h"
#include "llvm/Support/raw_ostream.h"

namespace clang {
namespace comments {

namespace {
class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> {
  raw_ostream &OS;
  SourceManager *SM;
  unsigned IndentLevel;

public:
  CommentDumper(raw_ostream &OS, SourceManager *SM) :
      OS(OS), SM(SM), IndentLevel(0)
  { }

  void dumpIndent() const {
    for (unsigned i = 1, e = IndentLevel; i < e; ++i)
      OS << "  ";
  }

  void dumpLocation(SourceLocation Loc) {
    if (SM)
      Loc.print(OS, *SM);
  }

  void dumpSourceRange(const Comment *C);

  void dumpComment(const Comment *C);

  void dumpSubtree(const Comment *C);

  // Inline content.
  void visitTextComment(const TextComment *C);
  void visitInlineCommandComment(const InlineCommandComment *C);
  void visitHTMLStartTagComment(const HTMLStartTagComment *C);
  void visitHTMLEndTagComment(const HTMLEndTagComment *C);

  // Block content.
  void visitParagraphComment(const ParagraphComment *C);
  void visitBlockCommandComment(const BlockCommandComment *C);
  void visitParamCommandComment(const ParamCommandComment *C);
  void visitVerbatimBlockComment(const VerbatimBlockComment *C);
  void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
  void visitVerbatimLineComment(const VerbatimLineComment *C);

  void visitFullComment(const FullComment *C);
};

void CommentDumper::dumpSourceRange(const Comment *C) {
  if (!SM)
    return;

  SourceRange SR = C->getSourceRange();

  OS << " <";
  dumpLocation(SR.getBegin());
  if (SR.getBegin() != SR.getEnd()) {
    OS << ", ";
    dumpLocation(SR.getEnd());
  }
  OS << ">";
}

void CommentDumper::dumpComment(const Comment *C) {
  dumpIndent();
  OS << "(" << C->getCommentKindName()
     << " " << (void *) C;
  dumpSourceRange(C);
}

void CommentDumper::dumpSubtree(const Comment *C) {
  ++IndentLevel;
  if (C) {
    visit(C);
    for (Comment::child_iterator I = C->child_begin(),
                                 E = C->child_end();
         I != E; ++I) {
      OS << '\n';
      dumpSubtree(*I);
    }
    OS << ')';
  } else {
    dumpIndent();
    OS << "<<<NULL>>>";
  }
  --IndentLevel;
}

void CommentDumper::visitTextComment(const TextComment *C) {
  dumpComment(C);

  OS << " Text=\"" << C->getText() << "\"";
}

void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) {
  dumpComment(C);

  OS << " Name=\"" << C->getCommandName() << "\"";
  switch (C->getRenderKind()) {
  case InlineCommandComment::RenderNormal:
    OS << " RenderNormal";
    break;
  case InlineCommandComment::RenderBold:
    OS << " RenderBold";
    break;
  case InlineCommandComment::RenderMonospaced:
    OS << " RenderMonospaced";
    break;
  case InlineCommandComment::RenderEmphasized:
    OS << " RenderEmphasized";
    break;
  }

  for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
    OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
}

void CommentDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
  dumpComment(C);

  OS << " Name=\"" << C->getTagName() << "\"";
  if (C->getNumAttrs() != 0) {
    OS << " Attrs: ";
    for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
      const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
      OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
    }
  }
  if (C->isSelfClosing())
    OS << " SelfClosing";
}

void CommentDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
  dumpComment(C);

  OS << " Name=\"" << C->getTagName() << "\"";
}

void CommentDumper::visitParagraphComment(const ParagraphComment *C) {
  dumpComment(C);
}

void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) {
  dumpComment(C);

  OS << " Name=\"" << C->getCommandName() << "\"";
  for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
    OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
}

void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) {
  dumpComment(C);

  OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());

  if (C->isDirectionExplicit())
    OS << " explicitly";
  else
    OS << " implicitly";

  if (C->hasParamName()) {
    OS << " Param=\"" << C->getParamName() << "\"";
  }
}

void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
  dumpComment(C);

  OS << " Name=\"" << C->getCommandName() << "\""
        " CloseName=\"" << C->getCloseName() << "\"";
}

void CommentDumper::visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C) {
  dumpComment(C);

  OS << " Text=\"" << C->getText() << "\"";
}

void CommentDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
  dumpComment(C);

  OS << " Text=\"" << C->getText() << "\"";
}

void CommentDumper::visitFullComment(const FullComment *C) {
  dumpComment(C);
}

} // unnamed namespace

void Comment::dump(llvm::raw_ostream &OS, SourceManager *SM) const {
  CommentDumper D(llvm::errs(), SM);
  D.dumpSubtree(this);
  llvm::errs() << '\n';
}

} // end namespace comments
} // end namespace clang

<commit_msg>Comment dumper: print \param parameter index if parameter name is resolved.<commit_after>//===--- CommentDumper.cpp - Dumping implementation for Comment ASTs ------===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "clang/AST/CommentVisitor.h"
#include "llvm/Support/raw_ostream.h"

namespace clang {
namespace comments {

namespace {
class CommentDumper: public comments::ConstCommentVisitor<CommentDumper> {
  raw_ostream &OS;
  SourceManager *SM;
  unsigned IndentLevel;

public:
  CommentDumper(raw_ostream &OS, SourceManager *SM) :
      OS(OS), SM(SM), IndentLevel(0)
  { }

  void dumpIndent() const {
    for (unsigned i = 1, e = IndentLevel; i < e; ++i)
      OS << "  ";
  }

  void dumpLocation(SourceLocation Loc) {
    if (SM)
      Loc.print(OS, *SM);
  }

  void dumpSourceRange(const Comment *C);

  void dumpComment(const Comment *C);

  void dumpSubtree(const Comment *C);

  // Inline content.
  void visitTextComment(const TextComment *C);
  void visitInlineCommandComment(const InlineCommandComment *C);
  void visitHTMLStartTagComment(const HTMLStartTagComment *C);
  void visitHTMLEndTagComment(const HTMLEndTagComment *C);

  // Block content.
  void visitParagraphComment(const ParagraphComment *C);
  void visitBlockCommandComment(const BlockCommandComment *C);
  void visitParamCommandComment(const ParamCommandComment *C);
  void visitVerbatimBlockComment(const VerbatimBlockComment *C);
  void visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C);
  void visitVerbatimLineComment(const VerbatimLineComment *C);

  void visitFullComment(const FullComment *C);
};

void CommentDumper::dumpSourceRange(const Comment *C) {
  if (!SM)
    return;

  SourceRange SR = C->getSourceRange();

  OS << " <";
  dumpLocation(SR.getBegin());
  if (SR.getBegin() != SR.getEnd()) {
    OS << ", ";
    dumpLocation(SR.getEnd());
  }
  OS << ">";
}

void CommentDumper::dumpComment(const Comment *C) {
  dumpIndent();
  OS << "(" << C->getCommentKindName()
     << " " << (void *) C;
  dumpSourceRange(C);
}

void CommentDumper::dumpSubtree(const Comment *C) {
  ++IndentLevel;
  if (C) {
    visit(C);
    for (Comment::child_iterator I = C->child_begin(),
                                 E = C->child_end();
         I != E; ++I) {
      OS << '\n';
      dumpSubtree(*I);
    }
    OS << ')';
  } else {
    dumpIndent();
    OS << "<<<NULL>>>";
  }
  --IndentLevel;
}

void CommentDumper::visitTextComment(const TextComment *C) {
  dumpComment(C);

  OS << " Text=\"" << C->getText() << "\"";
}

void CommentDumper::visitInlineCommandComment(const InlineCommandComment *C) {
  dumpComment(C);

  OS << " Name=\"" << C->getCommandName() << "\"";
  switch (C->getRenderKind()) {
  case InlineCommandComment::RenderNormal:
    OS << " RenderNormal";
    break;
  case InlineCommandComment::RenderBold:
    OS << " RenderBold";
    break;
  case InlineCommandComment::RenderMonospaced:
    OS << " RenderMonospaced";
    break;
  case InlineCommandComment::RenderEmphasized:
    OS << " RenderEmphasized";
    break;
  }

  for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
    OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
}

void CommentDumper::visitHTMLStartTagComment(const HTMLStartTagComment *C) {
  dumpComment(C);

  OS << " Name=\"" << C->getTagName() << "\"";
  if (C->getNumAttrs() != 0) {
    OS << " Attrs: ";
    for (unsigned i = 0, e = C->getNumAttrs(); i != e; ++i) {
      const HTMLStartTagComment::Attribute &Attr = C->getAttr(i);
      OS << " \"" << Attr.Name << "=\"" << Attr.Value << "\"";
    }
  }
  if (C->isSelfClosing())
    OS << " SelfClosing";
}

void CommentDumper::visitHTMLEndTagComment(const HTMLEndTagComment *C) {
  dumpComment(C);

  OS << " Name=\"" << C->getTagName() << "\"";
}

void CommentDumper::visitParagraphComment(const ParagraphComment *C) {
  dumpComment(C);
}

void CommentDumper::visitBlockCommandComment(const BlockCommandComment *C) {
  dumpComment(C);

  OS << " Name=\"" << C->getCommandName() << "\"";
  for (unsigned i = 0, e = C->getNumArgs(); i != e; ++i)
    OS << " Arg[" << i << "]=\"" << C->getArgText(i) << "\"";
}

void CommentDumper::visitParamCommandComment(const ParamCommandComment *C) {
  dumpComment(C);

  OS << " " << ParamCommandComment::getDirectionAsString(C->getDirection());

  if (C->isDirectionExplicit())
    OS << " explicitly";
  else
    OS << " implicitly";

  if (C->hasParamName())
    OS << " Param=\"" << C->getParamName() << "\"";

  if (C->isParamIndexValid())
    OS << " ParamIndex=" << C->getParamIndex();
}

void CommentDumper::visitVerbatimBlockComment(const VerbatimBlockComment *C) {
  dumpComment(C);

  OS << " Name=\"" << C->getCommandName() << "\""
        " CloseName=\"" << C->getCloseName() << "\"";
}

void CommentDumper::visitVerbatimBlockLineComment(const VerbatimBlockLineComment *C) {
  dumpComment(C);

  OS << " Text=\"" << C->getText() << "\"";
}

void CommentDumper::visitVerbatimLineComment(const VerbatimLineComment *C) {
  dumpComment(C);

  OS << " Text=\"" << C->getText() << "\"";
}

void CommentDumper::visitFullComment(const FullComment *C) {
  dumpComment(C);
}

} // unnamed namespace

void Comment::dump(llvm::raw_ostream &OS, SourceManager *SM) const {
  CommentDumper D(llvm::errs(), SM);
  D.dumpSubtree(this);
  llvm::errs() << '\n';
}

} // end namespace comments
} // end namespace clang

<|endoftext|>


<commit_before>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "perfetto/ext/base/subprocess.h"

#if PERFETTO_HAS_SUBPROCESS()
#include <thread>

#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>

#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/temp_file.h"
#include "test/gtest_and_gmock.h"

namespace perfetto {
namespace base {
namespace {

std::string GenLargeString() {
  std::string contents;
  for (int i = 0; i < 4096; i++) {
    contents += "very long text " + std::to_string(i) + "\n";
  }
  // Make sure that |contents| is > the default pipe buffer on Linux (4 pages).
  PERFETTO_DCHECK(contents.size() > 4096 * 4);
  return contents;
}

TEST(SubprocessTest, InvalidPath) {
  Subprocess p({"/usr/bin/invalid_1337"});
  EXPECT_FALSE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 128);
  EXPECT_EQ(p.output(), "execve() failed\n");
}

TEST(SubprocessTest, StdoutOnly) {
  Subprocess p({"sh", "-c", "(echo skip_err >&2); echo out_only"});
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.stderr_mode = Subprocess::kDevNull;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.output(), "out_only\n");
}

TEST(SubprocessTest, StderrOnly) {
  Subprocess p({"sh", "-c", "(echo err_only >&2); echo skip_out"});
  p.args.stdout_mode = Subprocess::kDevNull;
  p.args.stderr_mode = Subprocess::kBuffer;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.output(), "err_only\n");
}

TEST(SubprocessTest, BothStdoutAndStderr) {
  Subprocess p({"sh", "-c", "echo out; (echo err >&2); echo out2"});
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.stderr_mode = Subprocess::kBuffer;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.output(), "out\nerr\nout2\n");
}

TEST(SubprocessTest, BinTrue) {
  Subprocess p({"true"});
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 0);
}

TEST(SubprocessTest, BinFalse) {
  Subprocess p({"false"});
  EXPECT_FALSE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 1);
}

TEST(SubprocessTest, Echo) {
  Subprocess p({"echo", "-n", "foobar"});
  p.args.stdout_mode = Subprocess::kBuffer;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 0);
  EXPECT_EQ(p.output(), "foobar");
}

TEST(SubprocessTest, FeedbackLongInput) {
  std::string contents = GenLargeString();
  Subprocess p({"cat", "-"});
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.input = contents;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 0);
  EXPECT_EQ(p.output(), contents);
}

TEST(SubprocessTest, CatLargeFile) {
  std::string contents = GenLargeString();
  TempFile tf = TempFile::Create();
  WriteAll(tf.fd(), contents.data(), contents.size());
  FlushFile(tf.fd());
  Subprocess p({"cat", tf.path().c_str()});
  p.args.stdout_mode = Subprocess::kBuffer;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.output(), contents);
}

TEST(SubprocessTest, Timeout) {
  Subprocess p({"sleep", "60"});
  EXPECT_FALSE(p.Call(/*timeout_ms=*/1));
  EXPECT_EQ(p.status(), Subprocess::kKilledBySignal);
}

TEST(SubprocessTest, TimeoutNotHit) {
  Subprocess p({"sleep", "0.01"});
  EXPECT_TRUE(p.Call(/*timeout_ms=*/100000));
}

TEST(SubprocessTest, TimeoutStopOutput) {
  Subprocess p({"sh", "-c", "while true; do echo stuff; done"});
  p.args.stdout_mode = Subprocess::kDevNull;
  EXPECT_FALSE(p.Call(/*timeout_ms=*/10));
  EXPECT_EQ(p.status(), Subprocess::kKilledBySignal);
}

TEST(SubprocessTest, ExitBeforeReadingStdin) {
  // 'sh -c' is to avoid closing stdin (sleep closes it before sleeping).
  Subprocess p({"sh", "-c", "sleep 0.01"});
  p.args.stdout_mode = Subprocess::kDevNull;
  p.args.stderr_mode = Subprocess::kDevNull;
  p.args.input = GenLargeString();
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 0);
}

TEST(SubprocessTest, StdinWriteStall) {
  // 'sh -c' is to avoid closing stdin (sleep closes it before sleeping).
  // This causes a situation where the write on the stdin will stall because
  // nobody reads it and the pipe buffer fills up. In this situation we should
  // still handle the timeout properly.
  Subprocess p({"sh", "-c", "sleep 10"});
  p.args.stdout_mode = Subprocess::kDevNull;
  p.args.stderr_mode = Subprocess::kDevNull;
  p.args.input = GenLargeString();
  EXPECT_FALSE(p.Call(/*timeout_ms=*/10));
  EXPECT_EQ(p.status(), Subprocess::kKilledBySignal);
}

TEST(SubprocessTest, StartAndWait) {
  Subprocess p({"sleep", "1000"});
  p.Start();
  EXPECT_EQ(p.Poll(), Subprocess::kRunning);
  p.KillAndWaitForTermination();
  EXPECT_EQ(p.status(), Subprocess::kKilledBySignal);
  EXPECT_EQ(p.Poll(), Subprocess::kKilledBySignal);
  EXPECT_EQ(p.returncode(), 128 + SIGKILL);
}

#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID) && defined(ADDRESS_SANITIZER)
#define MAYBE_PollBehavesProperly DISABLED_PollBehavesProperly
#else
#define MAYBE_PollBehavesProperly PollBehavesProperly
#endif

// TODO(b/158484911): Re-enable once problem is fixed.
TEST(SubprocessTest, MAYBE_PollBehavesProperly) {
  Subprocess p({"sh", "-c", "echo foobar"});
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.input = "ignored";
  p.Start();

  // Here we use kill() as a way to tell if the process is still running.
  // SIGWINCH is ignored by default.
  while (kill(p.pid(), SIGWINCH) == 0) {
    usleep(1000);
  }

  // At this point Poll() must detect the termination.
  EXPECT_EQ(p.Poll(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 0);
}

// Test the case of passing a lambda in |entrypoint| but no cmd.c
TEST(SubprocessTest, Entrypoint) {
  Subprocess p;
  p.args.input = "ping\n";
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.entrypoint_for_testing = [] {
    char buf[32]{};
    PERFETTO_CHECK(fgets(buf, sizeof(buf), stdin));
    PERFETTO_CHECK(strcmp(buf, "ping\n") == 0);
    printf("pong\n");
    fflush(stdout);
    _exit(42);
  };
  EXPECT_FALSE(p.Call());
  EXPECT_EQ(p.returncode(), 42);
  EXPECT_EQ(p.output(), "pong\n");
}

// Test the case of passing both a lambda entrypoint and a process to exec.
TEST(SubprocessTest, EntrypointAndExec) {
  base::Pipe pipe1 = base::Pipe::Create();
  base::Pipe pipe2 = base::Pipe::Create();
  int pipe1_wr = *pipe1.wr;
  int pipe2_wr = *pipe2.wr;

  Subprocess p({"echo", "123"});
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.preserve_fds.push_back(pipe2_wr);
  p.args.entrypoint_for_testing = [pipe1_wr, pipe2_wr] {
    base::ignore_result(write(pipe1_wr, "fail", 4));
    base::ignore_result(write(pipe2_wr, "pass", 4));
  };

  p.Start();
  pipe1.wr.reset();
  pipe2.wr.reset();

  char buf[8];
  EXPECT_LE(read(*pipe1.rd, buf, sizeof(buf)), 0);
  EXPECT_EQ(read(*pipe2.rd, buf, sizeof(buf)), 4);
  buf[4] = '\0';
  EXPECT_STREQ(buf, "pass");
  EXPECT_TRUE(p.Wait());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.output(), "123\n");
}

TEST(SubprocessTest, Wait) {
  Subprocess p({"sleep", "10000"});
  p.Start();
  for (int i = 0; i < 3; i++) {
    EXPECT_FALSE(p.Wait(1 /*ms*/));
    EXPECT_EQ(p.status(), Subprocess::kRunning);
  }
  kill(p.pid(), SIGBUS);
  EXPECT_TRUE(p.Wait(30000 /*ms*/));
  EXPECT_TRUE(p.Wait());  // Should be a no-op.
  EXPECT_EQ(p.status(), Subprocess::kKilledBySignal);
  EXPECT_EQ(p.returncode(), 128 + SIGBUS);
}

TEST(SubprocessTest, KillOnDtor) {
  // Here we use kill(SIGWINCH) as a way to tell if the process is still alive.
  // SIGWINCH is one of the few signals that has default ignore disposition.
  int pid;
  {
    Subprocess p({"sleep", "10000"});
    p.Start();
    pid = p.pid();
    EXPECT_EQ(kill(pid, SIGWINCH), 0);
  }
  EXPECT_EQ(kill(pid, SIGWINCH), -1);
}

// Regression test for b/162505491.
TEST(SubprocessTest, MoveOperators) {
  {
    Subprocess initial = Subprocess({"sleep", "10000"});
    initial.Start();
    Subprocess moved(std::move(initial));
    EXPECT_EQ(moved.Poll(), Subprocess::kRunning);
    EXPECT_EQ(initial.Poll(), Subprocess::kNotStarted);

    // Check that reuse works
    initial = Subprocess({"echo", "-n", "hello"});
    initial.args.stdout_mode = Subprocess::OutputMode::kBuffer;
    initial.Start();
    initial.Wait(/*timeout=*/5000);
    EXPECT_EQ(initial.status(), Subprocess::kExited);
    EXPECT_EQ(initial.returncode(), 0);
    EXPECT_EQ(initial.output(), "hello");
  }

  std::vector<Subprocess> v;
  for (int i = 0; i < 10; i++) {
    v.emplace_back(Subprocess({"sleep", "10"}));
    v.back().Start();
  }
  for (auto& p : v)
    EXPECT_EQ(p.Poll(), Subprocess::kRunning);
}

}  // namespace
}  // namespace base
}  // namespace perfetto

#endif  // PERFETTO_HAS_SUBPROCESS()
<commit_msg>Disable PollBehavesProperly without ASAN.<commit_after>/*
 * Copyright (C) 2019 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "perfetto/ext/base/subprocess.h"

#if PERFETTO_HAS_SUBPROCESS()
#include <thread>

#include <signal.h>
#include <sys/stat.h>
#include <unistd.h>

#include "perfetto/ext/base/file_utils.h"
#include "perfetto/ext/base/temp_file.h"
#include "test/gtest_and_gmock.h"

namespace perfetto {
namespace base {
namespace {

std::string GenLargeString() {
  std::string contents;
  for (int i = 0; i < 4096; i++) {
    contents += "very long text " + std::to_string(i) + "\n";
  }
  // Make sure that |contents| is > the default pipe buffer on Linux (4 pages).
  PERFETTO_DCHECK(contents.size() > 4096 * 4);
  return contents;
}

TEST(SubprocessTest, InvalidPath) {
  Subprocess p({"/usr/bin/invalid_1337"});
  EXPECT_FALSE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 128);
  EXPECT_EQ(p.output(), "execve() failed\n");
}

TEST(SubprocessTest, StdoutOnly) {
  Subprocess p({"sh", "-c", "(echo skip_err >&2); echo out_only"});
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.stderr_mode = Subprocess::kDevNull;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.output(), "out_only\n");
}

TEST(SubprocessTest, StderrOnly) {
  Subprocess p({"sh", "-c", "(echo err_only >&2); echo skip_out"});
  p.args.stdout_mode = Subprocess::kDevNull;
  p.args.stderr_mode = Subprocess::kBuffer;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.output(), "err_only\n");
}

TEST(SubprocessTest, BothStdoutAndStderr) {
  Subprocess p({"sh", "-c", "echo out; (echo err >&2); echo out2"});
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.stderr_mode = Subprocess::kBuffer;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.output(), "out\nerr\nout2\n");
}

TEST(SubprocessTest, BinTrue) {
  Subprocess p({"true"});
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 0);
}

TEST(SubprocessTest, BinFalse) {
  Subprocess p({"false"});
  EXPECT_FALSE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 1);
}

TEST(SubprocessTest, Echo) {
  Subprocess p({"echo", "-n", "foobar"});
  p.args.stdout_mode = Subprocess::kBuffer;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 0);
  EXPECT_EQ(p.output(), "foobar");
}

TEST(SubprocessTest, FeedbackLongInput) {
  std::string contents = GenLargeString();
  Subprocess p({"cat", "-"});
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.input = contents;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 0);
  EXPECT_EQ(p.output(), contents);
}

TEST(SubprocessTest, CatLargeFile) {
  std::string contents = GenLargeString();
  TempFile tf = TempFile::Create();
  WriteAll(tf.fd(), contents.data(), contents.size());
  FlushFile(tf.fd());
  Subprocess p({"cat", tf.path().c_str()});
  p.args.stdout_mode = Subprocess::kBuffer;
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.output(), contents);
}

TEST(SubprocessTest, Timeout) {
  Subprocess p({"sleep", "60"});
  EXPECT_FALSE(p.Call(/*timeout_ms=*/1));
  EXPECT_EQ(p.status(), Subprocess::kKilledBySignal);
}

TEST(SubprocessTest, TimeoutNotHit) {
  Subprocess p({"sleep", "0.01"});
  EXPECT_TRUE(p.Call(/*timeout_ms=*/100000));
}

TEST(SubprocessTest, TimeoutStopOutput) {
  Subprocess p({"sh", "-c", "while true; do echo stuff; done"});
  p.args.stdout_mode = Subprocess::kDevNull;
  EXPECT_FALSE(p.Call(/*timeout_ms=*/10));
  EXPECT_EQ(p.status(), Subprocess::kKilledBySignal);
}

TEST(SubprocessTest, ExitBeforeReadingStdin) {
  // 'sh -c' is to avoid closing stdin (sleep closes it before sleeping).
  Subprocess p({"sh", "-c", "sleep 0.01"});
  p.args.stdout_mode = Subprocess::kDevNull;
  p.args.stderr_mode = Subprocess::kDevNull;
  p.args.input = GenLargeString();
  EXPECT_TRUE(p.Call());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 0);
}

TEST(SubprocessTest, StdinWriteStall) {
  // 'sh -c' is to avoid closing stdin (sleep closes it before sleeping).
  // This causes a situation where the write on the stdin will stall because
  // nobody reads it and the pipe buffer fills up. In this situation we should
  // still handle the timeout properly.
  Subprocess p({"sh", "-c", "sleep 10"});
  p.args.stdout_mode = Subprocess::kDevNull;
  p.args.stderr_mode = Subprocess::kDevNull;
  p.args.input = GenLargeString();
  EXPECT_FALSE(p.Call(/*timeout_ms=*/10));
  EXPECT_EQ(p.status(), Subprocess::kKilledBySignal);
}

TEST(SubprocessTest, StartAndWait) {
  Subprocess p({"sleep", "1000"});
  p.Start();
  EXPECT_EQ(p.Poll(), Subprocess::kRunning);
  p.KillAndWaitForTermination();
  EXPECT_EQ(p.status(), Subprocess::kKilledBySignal);
  EXPECT_EQ(p.Poll(), Subprocess::kKilledBySignal);
  EXPECT_EQ(p.returncode(), 128 + SIGKILL);
}

#if PERFETTO_BUILDFLAG(PERFETTO_OS_ANDROID)
#define MAYBE_PollBehavesProperly DISABLED_PollBehavesProperly
#else
#define MAYBE_PollBehavesProperly PollBehavesProperly
#endif

// TODO(b/158484911): Re-enable once problem is fixed.
TEST(SubprocessTest, MAYBE_PollBehavesProperly) {
  Subprocess p({"sh", "-c", "echo foobar"});
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.input = "ignored";
  p.Start();

  // Here we use kill() as a way to tell if the process is still running.
  // SIGWINCH is ignored by default.
  while (kill(p.pid(), SIGWINCH) == 0) {
    usleep(1000);
  }

  // At this point Poll() must detect the termination.
  EXPECT_EQ(p.Poll(), Subprocess::kExited);
  EXPECT_EQ(p.returncode(), 0);
}

// Test the case of passing a lambda in |entrypoint| but no cmd.c
TEST(SubprocessTest, Entrypoint) {
  Subprocess p;
  p.args.input = "ping\n";
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.entrypoint_for_testing = [] {
    char buf[32]{};
    PERFETTO_CHECK(fgets(buf, sizeof(buf), stdin));
    PERFETTO_CHECK(strcmp(buf, "ping\n") == 0);
    printf("pong\n");
    fflush(stdout);
    _exit(42);
  };
  EXPECT_FALSE(p.Call());
  EXPECT_EQ(p.returncode(), 42);
  EXPECT_EQ(p.output(), "pong\n");
}

// Test the case of passing both a lambda entrypoint and a process to exec.
TEST(SubprocessTest, EntrypointAndExec) {
  base::Pipe pipe1 = base::Pipe::Create();
  base::Pipe pipe2 = base::Pipe::Create();
  int pipe1_wr = *pipe1.wr;
  int pipe2_wr = *pipe2.wr;

  Subprocess p({"echo", "123"});
  p.args.stdout_mode = Subprocess::kBuffer;
  p.args.preserve_fds.push_back(pipe2_wr);
  p.args.entrypoint_for_testing = [pipe1_wr, pipe2_wr] {
    base::ignore_result(write(pipe1_wr, "fail", 4));
    base::ignore_result(write(pipe2_wr, "pass", 4));
  };

  p.Start();
  pipe1.wr.reset();
  pipe2.wr.reset();

  char buf[8];
  EXPECT_LE(read(*pipe1.rd, buf, sizeof(buf)), 0);
  EXPECT_EQ(read(*pipe2.rd, buf, sizeof(buf)), 4);
  buf[4] = '\0';
  EXPECT_STREQ(buf, "pass");
  EXPECT_TRUE(p.Wait());
  EXPECT_EQ(p.status(), Subprocess::kExited);
  EXPECT_EQ(p.output(), "123\n");
}

TEST(SubprocessTest, Wait) {
  Subprocess p({"sleep", "10000"});
  p.Start();
  for (int i = 0; i < 3; i++) {
    EXPECT_FALSE(p.Wait(1 /*ms*/));
    EXPECT_EQ(p.status(), Subprocess::kRunning);
  }
  kill(p.pid(), SIGBUS);
  EXPECT_TRUE(p.Wait(30000 /*ms*/));
  EXPECT_TRUE(p.Wait());  // Should be a no-op.
  EXPECT_EQ(p.status(), Subprocess::kKilledBySignal);
  EXPECT_EQ(p.returncode(), 128 + SIGBUS);
}

TEST(SubprocessTest, KillOnDtor) {
  // Here we use kill(SIGWINCH) as a way to tell if the process is still alive.
  // SIGWINCH is one of the few signals that has default ignore disposition.
  int pid;
  {
    Subprocess p({"sleep", "10000"});
    p.Start();
    pid = p.pid();
    EXPECT_EQ(kill(pid, SIGWINCH), 0);
  }
  EXPECT_EQ(kill(pid, SIGWINCH), -1);
}

// Regression test for b/162505491.
TEST(SubprocessTest, MoveOperators) {
  {
    Subprocess initial = Subprocess({"sleep", "10000"});
    initial.Start();
    Subprocess moved(std::move(initial));
    EXPECT_EQ(moved.Poll(), Subprocess::kRunning);
    EXPECT_EQ(initial.Poll(), Subprocess::kNotStarted);

    // Check that reuse works
    initial = Subprocess({"echo", "-n", "hello"});
    initial.args.stdout_mode = Subprocess::OutputMode::kBuffer;
    initial.Start();
    initial.Wait(/*timeout=*/5000);
    EXPECT_EQ(initial.status(), Subprocess::kExited);
    EXPECT_EQ(initial.returncode(), 0);
    EXPECT_EQ(initial.output(), "hello");
  }

  std::vector<Subprocess> v;
  for (int i = 0; i < 10; i++) {
    v.emplace_back(Subprocess({"sleep", "10"}));
    v.back().Start();
  }
  for (auto& p : v)
    EXPECT_EQ(p.Poll(), Subprocess::kRunning);
}

}  // namespace
}  // namespace base
}  // namespace perfetto

#endif  // PERFETTO_HAS_SUBPROCESS()
<|endoftext|>


<commit_before>#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <iostream>
#include <vector>

#include <gflags/gflags.h>
#include <glog/logging.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>

#include "sdk/sdk.h"
#include "sdk/db.h"
#include "sdk/table.h"

#include "util/env.h"
#include "util/coding.h"

char* StripWhite(char* line) {
    char *s, *t;
    for (s = line; whitespace(*s); s++);
    if (*s == 0)
        return s;
    t = s + strlen(s) - 1;
    while (t > s && whitespace(*t)) {
        t--;
    }
    *++t = '\0';
    return s;
}

std::string cmd_name[] = {
    "quit",
    "help",
    "OpenDatabase",
};

void HelpManue() {
    printf("========= usage ===========\n");
    printf("cmd: quit\n");
    printf("cmd: help\n");
    printf("cmd: CreateTable dbname tablename primary_key_type [index_name index_type]...\n");
    printf("===========================\n");
}

int CreateTableOp(std::vector<std::string>& cmd_vec) {
    // create db
    std::cout << "open db ..." << std::endl;
    mdt::Database* db;
    std::string db_name = cmd_vec[1];
    db = mdt::OpenDatabase(db_name);

    // create table
    std::cout << "create table ..." << std::endl;
    mdt::TableDescription table_desc;
    table_desc.table_name = cmd_vec[2];
    if (cmd_vec[3].compare("kBytes") != 0) {
        std::cout << "create table fail, primary key type not support!\n";
        return 0;
    }
    table_desc.primary_key_type = mdt::kBytes;

    int num_index = cmd_vec.size() - 4;
    if (num_index % 2 != 0) {
        std::cout << "create table fail, [index_name index_type] not match!\n";
        return 0;
    }
    for (int i = 0; i < num_index; i += 2) {
        mdt::IndexDescription table_index;
        table_index.index_name = cmd_vec[i + 4];
        if (cmd_vec[i + 5].compare("kBytes") != 0) {
            std::cout << "create table fail, index key: " << cmd_vec[i + 4]
                << ", key type not support!\n";
            return 0;
        }
        table_index.index_key_type = mdt::kBytes;
        table_desc.index_descriptor_list.push_back(table_index);
    }
    CreateTable(db, table_desc);
    return 0;
}

int main(int ac, char* av[]) {
    while (1) {
        char *line = readline("mdt:");
        char *cmd = StripWhite(line);
        std::string command(cmd, strlen(cmd));

        // split cmd
        std::vector<std::string> cmd_vec;
        boost::split(cmd_vec, command, boost::is_any_of(" "), boost::token_compress_on);
        if (cmd_vec.size() == 0) {
            free(line);
            continue;
        } else if (cmd_vec[0].compare("quit") == 0) {
            std::cout << "bye\n";
            return 0;
        } else if (cmd_vec[0].compare("help") == 0) {
            HelpManue();
            free(line);
            continue;
        } else if (cmd_vec[0].compare("CreateTable") == 0 && cmd_vec.size() >= 6) {
            // cmd: CreateTable dbname tablename primary_key_type [index_name index_type]...
            std::cout << "create table: dbname " << cmd_vec[1]
                << "tablename " << cmd_vec[2]
                << "\n";
            CreateTableOp(cmd_vec);
            free(line);
            continue;
        } else {
            std::cout << "cmd not known\n";
            free(line);
            continue;
        }

        std::cout << command
            << ", size " << cmd_vec.size()
            << ", cmd " << cmd_vec[0]
            << "\n";
        free(line);
    }
    return 0;
}
<commit_msg>#29 : add mdt-tool put/get<commit_after>#include <stdio.h>
#include <stdlib.h>
#include <readline/readline.h>
#include <readline/history.h>
#include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string/classification.hpp>
#include <iostream>
#include <vector>

#include <gflags/gflags.h>
#include <glog/logging.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/time.h>

#include "sdk/sdk.h"
#include "sdk/db.h"
#include "sdk/table.h"

#include "util/env.h"
#include "util/coding.h"

char* StripWhite(char* line) {
    char *s, *t;
    for (s = line; whitespace(*s); s++);
    if (*s == 0)
        return s;
    t = s + strlen(s) - 1;
    while (t > s && whitespace(*t)) {
        t--;
    }
    *++t = '\0';
    return s;
}

void HelpManue() {
    printf("========= usage ===========\n");
    printf("cmd: quit\n");
    printf("cmd: help\n");
    printf("cmd: CreateTable dbname tablename primary_key_type [index_name index_type]...\n");
    printf("cmd(TEST): Put dbname tablename value primary_key timestamp(ingore) [index_name index_key]...\n");
    printf("cmd: Get dbname tablename start_ts(ignore) end_ts(ignore) limit(ignore) "
            "[index_name cmp(=, >=, >, <=, <) index_key]...\n");
    printf("===========================\n");
}

int GetCmp(std::string& cmp_str) {
    if (cmp_str.compare(">") == 0) {
        return (int)mdt::kGreater;
    } else if (cmp_str.compare(">=") == 0) {
        return (int)mdt::kGreaterEqual;
    } else if (cmp_str.compare("<") == 0) {
        return (int)mdt::kLess;
    } else if (cmp_str.compare("<=") == 0) {
        return (int)mdt::kLessEqual;
    } else if (cmp_str.compare("==") == 0) {
        return (int)mdt::kEqualTo;
    } else {
        //std::cout << "cmp " << cmp_str << " not support\n";
        return -1;
    }
    return -1;
}

int GetOp(std::vector<std::string>& cmd_vec) {
    // create db
    std::cout << "open db ..." << std::endl;
    mdt::Database* db;
    std::string db_name = cmd_vec[1];
    db = mdt::OpenDatabase(db_name);

    std::cout << "open table ..." << std::endl;
    mdt::Table* table;
    std::string table_name = cmd_vec[2];
    table = OpenTable(db, table_name);

    // search test
    mdt::SearchRequest* search_req = new mdt::SearchRequest;
    search_req->start_timestamp = 0;
    search_req->end_timestamp = time(NULL);

    int num_index = cmd_vec.size() - 6;
    if (num_index % 3 != 0) {
        std::cout << "num of condition index not match\n";
        return 0;
    }
    for (int i = 0; i < num_index; i += 3) {
        mdt::IndexCondition index;
        int cmp;
        index.index_name = cmd_vec[i + 6];
        cmp = GetCmp(cmd_vec[i + 7]);
        if (cmp == -1) {
            std::cout << "cmp " << cmd_vec[i + 7] << " not support\n";
            return 0;
        }
        index.comparator = (mdt::COMPARATOR)cmp;
        index.compare_value = cmd_vec[i + 8];
        search_req->index_condition_list.push_back(index);
    }

    mdt::SearchResponse* search_resp = new mdt::SearchResponse;

    std::cout << "get ..." << std::endl;
    table->Get(search_req, search_resp);
    for (uint32_t i = 0; i < search_resp->result_stream.size(); i++) {
        const mdt::ResultStream& result = search_resp->result_stream[i];
        std::cout << "primary key: " << result.primary_key << std::endl;
        for (uint32_t j = 0; j < result.result_data_list.size(); j++) {
            std::cout << "        data: " << result.result_data_list[j] << std::endl;
        }
    }
    return 0;
}

void StoreCallback_Test(mdt::Table* table, mdt::StoreRequest* request,
                        mdt::StoreResponse* response,
                        void* callback_param) {
    bool* store_finish = (bool*)callback_param;
    *store_finish = true;
}

int PutOp(std::vector<std::string>& cmd_vec) {
    // create db
    std::cout << "open db ..." << std::endl;
    mdt::Database* db;
    std::string db_name = cmd_vec[1];
    db = mdt::OpenDatabase(db_name);

    std::cout << "open table ..." << std::endl;
    mdt::Table* table;
    std::string table_name = cmd_vec[2];
    table = OpenTable(db, table_name);

    if (cmd_vec[3].compare("1") != 0) {
        std::cout << "value type not support, now support value=1\n";
        return 0;
    }

    // insert data
    mdt::StoreRequest* store_req = new mdt::StoreRequest();
    store_req->primary_key = cmd_vec[4];
    store_req->timestamp = time(NULL);

    int num_index = cmd_vec.size() - 6;
    if (num_index % 2 != 0) {
        std::cout << "put fail, [index_name index_type] not match!\n";
        return 0;
    }
    for (int i = 0; i < num_index; i += 2) {
        mdt::Index index;
        index.index_name = cmd_vec[i + 6];
        index.index_key = cmd_vec[i + 7];
        store_req->index_list.push_back(index);
    }

    if (cmd_vec[3].compare("1") != 0) {
        std::string str(10240, 'y');
        store_req->data = str;
    }
    mdt::StoreResponse* store_resp = new mdt::StoreResponse();
    mdt::StoreCallback callback = StoreCallback_Test;

    bool store_finish = false;
    std::cout << "put ..." << std::endl;
    table->Put(store_req, store_resp, callback, &store_finish);
    return 0;
}

int CreateTableOp(std::vector<std::string>& cmd_vec) {
    // create db
    std::cout << "open db ..." << std::endl;
    mdt::Database* db;
    std::string db_name = cmd_vec[1];
    db = mdt::OpenDatabase(db_name);

    // create table
    std::cout << "create table ..." << std::endl;
    mdt::TableDescription table_desc;
    table_desc.table_name = cmd_vec[2];
    if (cmd_vec[3].compare("kBytes") != 0) {
        std::cout << "create table fail, primary key type not support!\n";
        return 0;
    }
    table_desc.primary_key_type = mdt::kBytes;

    int num_index = cmd_vec.size() - 4;
    if (num_index % 2 != 0) {
        std::cout << "create table fail, [index_name index_type] not match!\n";
        return 0;
    }
    for (int i = 0; i < num_index; i += 2) {
        mdt::IndexDescription table_index;
        table_index.index_name = cmd_vec[i + 4];
        if (cmd_vec[i + 5].compare("kBytes") != 0) {
            std::cout << "create table fail, index key: " << cmd_vec[i + 4]
                << ", key type not support!\n";
            return 0;
        }
        table_index.index_key_type = mdt::kBytes;
        table_desc.index_descriptor_list.push_back(table_index);
    }
    CreateTable(db, table_desc);
    return 0;
}

int main(int ac, char* av[]) {
    while (1) {
        char *line = readline("mdt:");
        char *cmd = StripWhite(line);
        std::string command(cmd, strlen(cmd));

        // split cmd
        std::vector<std::string> cmd_vec;
        boost::split(cmd_vec, command, boost::is_any_of(" "), boost::token_compress_on);
        if (cmd_vec.size() == 0) {
            free(line);
            continue;
        } else if (cmd_vec[0].compare("quit") == 0) {
            std::cout << "bye\n";
            return 0;
        } else if (cmd_vec[0].compare("help") == 0) {
            HelpManue();
            free(line);
            continue;
        } else if (cmd_vec[0].compare("CreateTable") == 0 && cmd_vec.size() >= 6) {
            // cmd: CreateTable dbname tablename primary_key_type [index_name index_type]...
            std::cout << "create table: dbname " << cmd_vec[1]
                << "tablename " << cmd_vec[2]
                << "\n";
            CreateTableOp(cmd_vec);
            free(line);
            continue;
        } else if (cmd_vec[0].compare("Put") == 0 && cmd_vec.size() >= 6) {
            // cmd: Put dbname tablename value primary_key timestamp [index_name index_key]
            PutOp(cmd_vec);
            free(line);
            continue;
        } else if (cmd_vec[0].compare("Get") == 0 && cmd_vec.size() >= 9) {
            // cmd: Get dbname tablename start_ts(ignore) end_ts(ignore) limit(ignore) [index_name cmp(=, >=, >, <=, <) index_key]
            GetOp(cmd_vec);
            free(line);
            continue;
        } else {
            std::cout << "cmd not known\n";
            free(line);
            continue;
        }

        std::cout << command
            << ", size " << cmd_vec.size()
            << ", cmd " << cmd_vec[0]
            << "\n";
        free(line);
    }
    return 0;
}
<|endoftext|>