<commit_before>
/// \author James Hughes
/// \date   November 2013

#include "SpireTestFixture.hpp"

#include <spire/src/FileUtil.h>
#include <spire/src/GLMathUtil.h>

namespace CPM_GL_BATCH_TESTING_NS {

//------------------------------------------------------------------------------
void SpireTestFixture::SetUp()
{
  // Build spire using the context from GlobalTestEnvironment.
  std::shared_ptr<BatchEnvironment> ctx
      = GlobalTestEnvironment::instance()->getBatchEnvironment();
  ctx->makeCurrent();

  std::vector<std::string> shaderSearchDirs;
  shaderSearchDirs.push_back("shaders");

  mSpireContext = std::shared_ptr<SpireContext>(new SpireContext(ctx));
  mSpire = std::shared_ptr<CPM_SPIRE_NS::Interface>(
      new CPM_SPIRE_NS::Interface(mSpireContext, shaderSearchDirs));

  // Add default attributes.
  addDefaultAttributes();

  // Begin a new frame.
  beginFrame();
}

//------------------------------------------------------------------------------
void SpireTestFixture::TearDown()
{
  mSpire.reset();
  mSpireContext.reset();
}

//------------------------------------------------------------------------------
void SpireTestFixture::addDefaultAttributes()
{
  mSpire->addShaderAttribute("aPos",         3,  false,  sizeof(float) * 3,  CPM_SPIRE_NS::Interface::TYPE_FLOAT);
  mSpire->addShaderAttribute("aNormal",      3,  false,  sizeof(float) * 3,  CPM_SPIRE_NS::Interface::TYPE_FLOAT);
  mSpire->addShaderAttribute("aColorFloat",  4,  false,  sizeof(float) * 4,  CPM_SPIRE_NS::Interface::TYPE_FLOAT);
  mSpire->addShaderAttribute("aColor",       4,  true,   sizeof(char) * 4,   CPM_SPIRE_NS::Interface::TYPE_UBYTE);

  // Used to test attribute mis-alignment.
  mSpire->addShaderAttribute("aFieldData",   1,  false,  sizeof(float) * 1,  CPM_SPIRE_NS::Interface::TYPE_FLOAT);
}

//------------------------------------------------------------------------------
void SpireTestFixture::beginFrame()
{
  // Do not even attempt to render if the framebuffer is not complete.
  // This can happen when the rendering window is hidden (in SCIRun5 for
  // example);
  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  {
    std::cerr << "Incomplete framebuffer!" << std::endl;
    return;
  }

  /// \todo Move this outside of the interface!
  GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
  GL(glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT));

  CPM_SPIRE_NS::GPUState defaultGPUState;
  mSpire->applyGPUState(defaultGPUState, true); // true = force application of state.
}

//------------------------------------------------------------------------------
void SpireTestFixture::compareFBOWithExistingFile(
    const std::string& filename,
    const std::string& outputDir,
    const std::string& compareDir,
    const std::string& binary,
    int pixelThreshold)
{
  // Print out the frame and compare it.
  std::string imageName = filename;

  std::string targetImage = outputDir;
  targetImage += "/" + imageName;
  GlobalTestEnvironment::instance()->getBatchEnvironment()->writeFBO(targetImage);

  EXPECT_TRUE(CPM_SPIRE_NS::fileExists(targetImage)) << "Failed to write output image! " << targetImage;

  // Perform the perceptual comparison using the given regression directory.
  std::string compImage = compareDir;
  compImage += "/" + imageName;

  ASSERT_TRUE(CPM_SPIRE_NS::fileExists(compImage)) << "Failed to find comparison image! " << compImage;
  // Test using perceptual comparison program that the user has provided
  // (hopefully).
  std::stringstream ss;
  ss << binary << " -threshold " << pixelThreshold << " " << targetImage << " " << compImage;
  std::string command = ss.str();

  // Usually the return code of std::system is implementation specific. But the
  // majority of systems end up returning the exit code of the program.
  if (std::system(command.c_str()) != 0)
  {
    // The images are NOT the same. Alert the user.
    FAIL() << "Perceptual compare of " << imageName << " failed.";
  }
}

//------------------------------------------------------------------------------
// SpireContext implementation
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SpireContext::SpireContext(std::shared_ptr<BatchEnvironment> env) :
    mEnv(env)
{ }

//------------------------------------------------------------------------------
void SpireContext::makeCurrent()
{
  mEnv->makeCurrent();
}

//------------------------------------------------------------------------------
void SpireContext::swapBuffers()
{
  mEnv->swapBuffers();
}

} // namespace CPM_GL_BATCH_TESTING_NS

<commit_msg>Adding note regarding GPUState removal in future versions of spire.<commit_after>
/// \author James Hughes
/// \date   November 2013

#include "SpireTestFixture.hpp"

#include <spire/src/FileUtil.h>
#include <spire/src/GLMathUtil.h>

namespace CPM_GL_BATCH_TESTING_NS {

//------------------------------------------------------------------------------
void SpireTestFixture::SetUp()
{
  // Build spire using the context from GlobalTestEnvironment.
  std::shared_ptr<BatchEnvironment> ctx
      = GlobalTestEnvironment::instance()->getBatchEnvironment();
  ctx->makeCurrent();

  std::vector<std::string> shaderSearchDirs;
  shaderSearchDirs.push_back("shaders");

  mSpireContext = std::shared_ptr<SpireContext>(new SpireContext(ctx));
  mSpire = std::shared_ptr<CPM_SPIRE_NS::Interface>(
      new CPM_SPIRE_NS::Interface(mSpireContext, shaderSearchDirs));

  // Add default attributes.
  addDefaultAttributes();

  // Begin a new frame.
  beginFrame();
}

//------------------------------------------------------------------------------
void SpireTestFixture::TearDown()
{
  mSpire.reset();
  mSpireContext.reset();
}

//------------------------------------------------------------------------------
void SpireTestFixture::addDefaultAttributes()
{
  mSpire->addShaderAttribute("aPos",         3,  false,  sizeof(float) * 3,  CPM_SPIRE_NS::Interface::TYPE_FLOAT);
  mSpire->addShaderAttribute("aNormal",      3,  false,  sizeof(float) * 3,  CPM_SPIRE_NS::Interface::TYPE_FLOAT);
  mSpire->addShaderAttribute("aColorFloat",  4,  false,  sizeof(float) * 4,  CPM_SPIRE_NS::Interface::TYPE_FLOAT);
  mSpire->addShaderAttribute("aColor",       4,  true,   sizeof(char) * 4,   CPM_SPIRE_NS::Interface::TYPE_UBYTE);

  // Used to test attribute mis-alignment.
  mSpire->addShaderAttribute("aFieldData",   1,  false,  sizeof(float) * 1,  CPM_SPIRE_NS::Interface::TYPE_FLOAT);
}

//------------------------------------------------------------------------------
void SpireTestFixture::beginFrame()
{
  // Do not even attempt to render if the framebuffer is not complete.
  // This can happen when the rendering window is hidden (in SCIRun5 for
  // example);
  if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE)
  {
    std::cerr << "Incomplete framebuffer!" << std::endl;
    return;
  }

  /// \todo Move this outside of the interface!
  GL(glClearColor(0.0f, 0.0f, 0.0f, 1.0f));
  GL(glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT));

  /// \xxx GPUState will be removed in future versions of spire!
  CPM_SPIRE_NS::GPUState defaultGPUState;
  mSpire->applyGPUState(defaultGPUState, true); // true = force application of state.
}

//------------------------------------------------------------------------------
void SpireTestFixture::compareFBOWithExistingFile(
    const std::string& filename,
    const std::string& outputDir,
    const std::string& compareDir,
    const std::string& binary,
    int pixelThreshold)
{
  // Print out the frame and compare it.
  std::string imageName = filename;

  std::string targetImage = outputDir;
  targetImage += "/" + imageName;
  GlobalTestEnvironment::instance()->getBatchEnvironment()->writeFBO(targetImage);

  EXPECT_TRUE(CPM_SPIRE_NS::fileExists(targetImage)) << "Failed to write output image! " << targetImage;

  // Perform the perceptual comparison using the given regression directory.
  std::string compImage = compareDir;
  compImage += "/" + imageName;

  ASSERT_TRUE(CPM_SPIRE_NS::fileExists(compImage)) << "Failed to find comparison image! " << compImage;
  // Test using perceptual comparison program that the user has provided
  // (hopefully).
  std::stringstream ss;
  ss << binary << " -threshold " << pixelThreshold << " " << targetImage << " " << compImage;
  std::string command = ss.str();

  // Usually the return code of std::system is implementation specific. But the
  // majority of systems end up returning the exit code of the program.
  if (std::system(command.c_str()) != 0)
  {
    // The images are NOT the same. Alert the user.
    FAIL() << "Perceptual compare of " << imageName << " failed.";
  }
}

//------------------------------------------------------------------------------
// SpireContext implementation
//------------------------------------------------------------------------------

//------------------------------------------------------------------------------
SpireContext::SpireContext(std::shared_ptr<BatchEnvironment> env) :
    mEnv(env)
{ }

//------------------------------------------------------------------------------
void SpireContext::makeCurrent()
{
  mEnv->makeCurrent();
}

//------------------------------------------------------------------------------
void SpireContext::swapBuffers()
{
  mEnv->swapBuffers();
}

} // namespace CPM_GL_BATCH_TESTING_NS

<|endoftext|>


<commit_before>// Copyright 2013 Cloudera Inc.
//
// 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 "service/query-exec-state.h"
#include "service/impala-server.h"
#include "service/frontend.h"

#include "exec/ddl-executor.h"
#include "exprs/expr.h"
#include "runtime/row-batch.h"
#include "util/debug-util.h"

using namespace std;
using namespace boost;
using namespace boost::uuids;
using namespace beeswax;

namespace impala {

ImpalaServer::QueryExecState::QueryExecState(
    ExecEnv* exec_env, Frontend* frontend,
    shared_ptr<SessionState> session,
    const TSessionState& query_session_state, const string& sql_stmt)
  : sql_stmt_(sql_stmt),
    exec_env_(exec_env),
    parent_session_(session),
    query_session_state_(query_session_state),
    coord_(NULL),
    profile_(&profile_pool_, "Query"),  // assign name w/ id after planning
    server_profile_(&profile_pool_, "ImpalaServer"),
    summary_profile_(&profile_pool_, "Summary"),
    eos_(false),
    query_state_(beeswax::QueryState::CREATED),
    current_batch_(NULL),
    current_batch_row_(0),
    num_rows_fetched_(0),
    frontend_(frontend),
    start_time_(TimestampValue::local_time_micros()) {
  row_materialization_timer_ = ADD_TIMER(&server_profile_, "RowMaterializationTimer");
  client_wait_timer_ = ADD_TIMER(&server_profile_, "ClientFetchWaitTimer");
  query_events_ = summary_profile_.AddEventSequence("Query Timeline");
  query_events_->Start();
  profile_.AddChild(&summary_profile_);
  profile_.AddChild(&server_profile_);

  // Creating a random_generator every time is not free, but
  // benchmarks show it to be slightly cheaper than contending for a
  // single generator under a lock (since random_generator is not
  // thread-safe).
  random_generator uuid_generator;
  uuid query_uuid = uuid_generator();
  query_id_.hi = *reinterpret_cast<uint64_t*>(&query_uuid.data[0]);
  query_id_.lo = *reinterpret_cast<uint64_t*>(&query_uuid.data[8]);

  summary_profile_.AddInfoString("Start Time", start_time().DebugString());
  summary_profile_.AddInfoString("End Time", "");
  summary_profile_.AddInfoString("Query Type", "N/A");
  summary_profile_.AddInfoString("Query State", PrintQueryState(query_state_));
  summary_profile_.AddInfoString("Query Status", "OK");
  summary_profile_.AddInfoString("Impala Version", GetVersionString(/* compact */ true));
  summary_profile_.AddInfoString("User", user());
  summary_profile_.AddInfoString("Default Db", default_db());
  summary_profile_.AddInfoString("Sql Statement", sql_stmt);
}

Status ImpalaServer::QueryExecState::Exec(TExecRequest* exec_request) {
  exec_request_ = *exec_request;
  profile_.set_name("Query (id=" + PrintId(query_id()) + ")");

  summary_profile_.AddInfoString("Query Type", PrintTStmtType(stmt_type()));
  summary_profile_.AddInfoString("Query State", PrintQueryState(query_state_));

  switch (exec_request->stmt_type) {
    case TStmtType::QUERY:
    case TStmtType::DML:
      return ExecQueryOrDmlRequest();
    case TStmtType::EXPLAIN: {
      request_result_set_.reset(new vector<TResultRow>(
          exec_request_.explain_result.results));
      return Status::OK;
    }
    case TStmtType::DDL: {
      if (exec_request_.ddl_exec_request.ddl_type == TDdlType::USE) {
        lock_guard<mutex> l(parent_session_->lock);
        parent_session_->database = exec_request_.ddl_exec_request.use_db_params.db;
        return Status::OK;
      }
      ddl_executor_.reset(new DdlExecutor(frontend_));
      Status status = ddl_executor_->Exec(exec_request_.ddl_exec_request,
          query_session_state_);
      {
        lock_guard<mutex> l(lock_);
        return UpdateQueryStatus(status);
      }
    }
    case TStmtType::LOAD: {
      DCHECK(exec_request_.__isset.load_data_request);
      TLoadDataResp response;
      RETURN_IF_ERROR(
          frontend_->LoadData(exec_request_.load_data_request, &response));
      request_result_set_.reset(new vector<TResultRow>);
      request_result_set_->push_back(response.load_summary);
      return Status::OK;
    }
    default:
      stringstream errmsg;
      errmsg << "Unknown  exec request stmt type: " << exec_request->stmt_type;
      return Status(errmsg.str());
  }
}

Status ImpalaServer::QueryExecState::ExecQueryOrDmlRequest() {
  DCHECK(exec_request_.__isset.query_exec_request);
  TQueryExecRequest& query_exec_request = exec_request_.query_exec_request;

  // we always need at least one plan fragment
  DCHECK_GT(query_exec_request.fragments.size(), 0);

  if (query_exec_request.__isset.query_plan) {
    stringstream plan_ss;
    // Add some delimiters to make it clearer where the plan
    // begins and the profile ends
    plan_ss << "\n----------------\n"
            << query_exec_request.query_plan
            << "----------------";
    summary_profile_.AddInfoString("Plan", plan_ss.str());
  }

  // If desc_tbl is not set, query has SELECT with no FROM. In that
  // case, the query can only have a single fragment, and that fragment needs to be
  // executed by the coordinator. This check confirms that.
  // If desc_tbl is set, the query may or may not have a coordinator fragment.
  bool has_coordinator_fragment =
      query_exec_request.fragments[0].partition.type == TPartitionType::UNPARTITIONED;
  DCHECK(has_coordinator_fragment || query_exec_request.__isset.desc_tbl);

  // If the first fragment has a "limit 0", simply set EOS to true and return.
  // TODO: Remove this check if this is an INSERT. To be compatible with
  // Hive, OVERWRITE inserts must clear out target tables / static
  // partitions even if no rows are written.
  DCHECK(query_exec_request.fragments[0].__isset.plan);
  if (query_exec_request.fragments[0].plan.nodes[0].limit == 0) {
    eos_ = true;
    return Status::OK;
  }

  coord_.reset(new Coordinator(exec_env_));
  Status status = coord_->Exec(
      query_id_, &query_exec_request, exec_request_.query_options, &output_exprs_);
  {
    lock_guard<mutex> l(lock_);
    RETURN_IF_ERROR(UpdateQueryStatus(status));
  }

  profile_.AddChild(coord_->query_profile());
  return Status::OK;
}

void ImpalaServer::QueryExecState::Done() {
  end_time_ = TimestampValue::local_time_micros();
  summary_profile_.AddInfoString("End Time", end_time().DebugString());
  summary_profile_.AddInfoString("Query State", PrintQueryState(query_state_));
  query_events_->MarkEvent("Unregister query");
}

Status ImpalaServer::QueryExecState::Exec(const TMetadataOpRequest& exec_request) {
  ddl_executor_.reset(new DdlExecutor(frontend_));
  RETURN_IF_ERROR(ddl_executor_->Exec(exec_request));
  result_metadata_ = ddl_executor_->result_set_metadata();
  return Status::OK;
}

Status ImpalaServer::QueryExecState::Wait() {
  if (coord_.get() != NULL) {
    RETURN_IF_ERROR(coord_->Wait());
    RETURN_IF_ERROR(UpdateMetastore());
  }

  if (!returns_result_set()) {
    // Queries that do not return a result are finished at this point. This includes
    // DML operations and a subset of the DDL operations.
    eos_ = true;
  } else {
    // Rows are available now, so start the 'wait' timer that tracks how
    // long Impala waits for the client to fetch rows.
    client_wait_sw_.Start();
  }

  return Status::OK;
}

Status ImpalaServer::QueryExecState::FetchRows(const int32_t max_rows,
    QueryResultSet* fetched_rows) {
  // Pause the wait timer, since the client has instructed us to do
  // work on its behalf.
  client_wait_sw_.Stop();
  int64_t elapsed_time = client_wait_sw_.ElapsedTime();
  client_wait_timer_->Set(elapsed_time);

  // FetchInternal has already taken our lock_
  UpdateQueryStatus(FetchRowsInternal(max_rows, fetched_rows));

  // If all rows have been returned, no point in continuing the timer
  // to wait for the next call to FetchRows, which should never come.
  if (!eos_) client_wait_sw_.Start();
  return query_status_;
}

void ImpalaServer::QueryExecState::UpdateQueryState(QueryState::type query_state) {
  lock_guard<mutex> l(lock_);
  if (query_state_ < query_state) query_state_ = query_state;
}

Status ImpalaServer::QueryExecState::UpdateQueryStatus(const Status& status) {
  // Preserve the first non-ok status
  if (!status.ok() && query_status_.ok()) {
    query_state_ = QueryState::EXCEPTION;
    query_status_ = status;
    summary_profile_.AddInfoString("Query Status", query_status_.GetErrorMsg());
  }

  return status;
}

Status ImpalaServer::QueryExecState::FetchRowsInternal(const int32_t max_rows,
    QueryResultSet* fetched_rows) {
  DCHECK(query_state_ != QueryState::EXCEPTION);

  if (eos_) return Status::OK;

  if (ddl_executor_ != NULL || request_result_set_ != NULL) {
    // DDL / EXPLAIN / LOAD
    DCHECK(ddl_executor_ == NULL || request_result_set_ == NULL);
    query_state_ = QueryState::FINISHED;
    int num_rows = 0;
    const vector<TResultRow>& all_rows = (ddl_executor_ != NULL) ?
        ddl_executor_->result_set() : (*(request_result_set_.get()));
    // max_rows <= 0 means no limit
    while ((num_rows < max_rows || max_rows <= 0)
        && num_rows_fetched_ < all_rows.size()) {
      fetched_rows->AddOneRow(all_rows[num_rows_fetched_]);
      ++num_rows_fetched_;
      ++num_rows;
    }
    eos_ = (num_rows_fetched_ == all_rows.size());
    return Status::OK;
  }

  // List of expr values to hold evaluated rows from the query
  vector<void*> result_row;
  result_row.resize(output_exprs_.size());

  // List of scales for floating point values in result_row
  vector<int> scales;
  scales.resize(result_row.size());

  if (coord_ == NULL) {
    // query without FROM clause: we return exactly one row
    query_state_ = QueryState::FINISHED;
    eos_ = true;
    RETURN_IF_ERROR(GetRowValue(NULL, &result_row, &scales));
    return fetched_rows->AddOneRow(result_row, scales);
  }

  // query with a FROM clause
  RETURN_IF_ERROR(coord_->Wait());
  query_state_ = QueryState::FINISHED;  // results will be ready after this call
  // Fetch the next batch if we've returned the current batch entirely
  if (current_batch_ == NULL || current_batch_row_ >= current_batch_->num_rows()) {
    RETURN_IF_ERROR(FetchNextBatch());
  }
  if (current_batch_ == NULL) return Status::OK;

  {
    SCOPED_TIMER(row_materialization_timer_);
    // Convert the available rows, limited by max_rows
    int available = current_batch_->num_rows() - current_batch_row_;
    int fetched_count = available;
    // max_rows <= 0 means no limit
    if (max_rows > 0 && max_rows < available) fetched_count = max_rows;
    for (int i = 0; i < fetched_count; ++i) {
      TupleRow* row = current_batch_->GetRow(current_batch_row_);
      RETURN_IF_ERROR(GetRowValue(row, &result_row, &scales));
      RETURN_IF_ERROR(fetched_rows->AddOneRow(result_row, scales));
      ++num_rows_fetched_;
      ++current_batch_row_;
    }
  }
  return Status::OK;
}

Status ImpalaServer::QueryExecState::GetRowValue(TupleRow* row, vector<void*>* result,
                                                 vector<int>* scales) {
  DCHECK(result->size() >= output_exprs_.size());
  for (int i = 0; i < output_exprs_.size(); ++i) {
    (*result)[i] = output_exprs_[i]->GetValue(row);
    (*scales)[i] = output_exprs_[i]->output_scale();
  }
  return Status::OK;
}

void ImpalaServer::QueryExecState::Cancel() {
  // If the query is completed, no need to cancel.
  if (eos_) return;
  // we don't want multiple concurrent cancel calls to end up executing
  // Coordinator::Cancel() multiple times
  if (query_state_ == QueryState::EXCEPTION) return;
  query_state_ = QueryState::EXCEPTION;
  if (coord_.get() != NULL) coord_->Cancel();
}

Status ImpalaServer::QueryExecState::UpdateMetastore() {
  if (stmt_type() != TStmtType::DML) return Status::OK;

  DCHECK(exec_request().__isset.query_exec_request);
  TQueryExecRequest query_exec_request = exec_request().query_exec_request;
  if (!query_exec_request.__isset.finalize_params) return Status::OK;

  TFinalizeParams& finalize_params = query_exec_request.finalize_params;
  TCatalogUpdate catalog_update;
  if (!coord()->PrepareCatalogUpdate(&catalog_update)) {
    VLOG_QUERY << "No partitions altered, not updating metastore (query id: "
               << query_id() << ")";
  } else {
    // TODO: We track partitions written to, not created, which means
    // that we do more work than is necessary, because written-to
    // partitions don't always require a metastore change.
    VLOG_QUERY << "Updating metastore with " << catalog_update.created_partitions.size()
               << " altered partitions ("
               << join (catalog_update.created_partitions, ", ") << ")";

    catalog_update.target_table = finalize_params.table_name;
    catalog_update.db_name = finalize_params.table_db;
    RETURN_IF_ERROR(frontend_->UpdateMetastore(catalog_update));
  }
  return Status::OK;
}

Status ImpalaServer::QueryExecState::FetchNextBatch() {
  DCHECK(!eos_);
  DCHECK(coord_.get() != NULL);

  RETURN_IF_ERROR(coord_->GetNext(&current_batch_, coord_->runtime_state()));
  current_batch_row_ = 0;
  eos_ = current_batch_ == NULL;
  return Status::OK;
}

}
<commit_msg>IMPALA-429: Add query ID to profiles for queries that fail analysis<commit_after>// Copyright 2013 Cloudera Inc.
//
// 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 "service/query-exec-state.h"
#include "service/impala-server.h"
#include "service/frontend.h"

#include "exec/ddl-executor.h"
#include "exprs/expr.h"
#include "runtime/row-batch.h"
#include "util/debug-util.h"

using namespace std;
using namespace boost;
using namespace boost::uuids;
using namespace beeswax;

namespace impala {

ImpalaServer::QueryExecState::QueryExecState(
    ExecEnv* exec_env, Frontend* frontend,
    shared_ptr<SessionState> session,
    const TSessionState& query_session_state, const string& sql_stmt)
  : sql_stmt_(sql_stmt),
    exec_env_(exec_env),
    parent_session_(session),
    query_session_state_(query_session_state),
    coord_(NULL),
    profile_(&profile_pool_, "Query"),  // assign name w/ id after planning
    server_profile_(&profile_pool_, "ImpalaServer"),
    summary_profile_(&profile_pool_, "Summary"),
    eos_(false),
    query_state_(beeswax::QueryState::CREATED),
    current_batch_(NULL),
    current_batch_row_(0),
    num_rows_fetched_(0),
    frontend_(frontend),
    start_time_(TimestampValue::local_time_micros()) {
  row_materialization_timer_ = ADD_TIMER(&server_profile_, "RowMaterializationTimer");
  client_wait_timer_ = ADD_TIMER(&server_profile_, "ClientFetchWaitTimer");
  query_events_ = summary_profile_.AddEventSequence("Query Timeline");
  query_events_->Start();
  profile_.AddChild(&summary_profile_);

  // Creating a random_generator every time is not free, but
  // benchmarks show it to be slightly cheaper than contending for a
  // single generator under a lock (since random_generator is not
  // thread-safe).
  random_generator uuid_generator;
  uuid query_uuid = uuid_generator();
  query_id_.hi = *reinterpret_cast<uint64_t*>(&query_uuid.data[0]);
  query_id_.lo = *reinterpret_cast<uint64_t*>(&query_uuid.data[8]);

  profile_.set_name("Query (id=" + PrintId(query_id()) + ")");
  summary_profile_.AddInfoString("Start Time", start_time().DebugString());
  summary_profile_.AddInfoString("End Time", "");
  summary_profile_.AddInfoString("Query Type", "N/A");
  summary_profile_.AddInfoString("Query State", PrintQueryState(query_state_));
  summary_profile_.AddInfoString("Query Status", "OK");
  summary_profile_.AddInfoString("Impala Version", GetVersionString(/* compact */ true));
  summary_profile_.AddInfoString("User", user());
  summary_profile_.AddInfoString("Default Db", default_db());
  summary_profile_.AddInfoString("Sql Statement", sql_stmt);
}

Status ImpalaServer::QueryExecState::Exec(TExecRequest* exec_request) {
  exec_request_ = *exec_request;

  profile_.AddChild(&server_profile_);
  summary_profile_.AddInfoString("Query Type", PrintTStmtType(stmt_type()));
  summary_profile_.AddInfoString("Query State", PrintQueryState(query_state_));

  switch (exec_request->stmt_type) {
    case TStmtType::QUERY:
    case TStmtType::DML:
      return ExecQueryOrDmlRequest();
    case TStmtType::EXPLAIN: {
      request_result_set_.reset(new vector<TResultRow>(
          exec_request_.explain_result.results));
      return Status::OK;
    }
    case TStmtType::DDL: {
      if (exec_request_.ddl_exec_request.ddl_type == TDdlType::USE) {
        lock_guard<mutex> l(parent_session_->lock);
        parent_session_->database = exec_request_.ddl_exec_request.use_db_params.db;
        return Status::OK;
      }
      ddl_executor_.reset(new DdlExecutor(frontend_));
      Status status = ddl_executor_->Exec(exec_request_.ddl_exec_request,
          query_session_state_);
      {
        lock_guard<mutex> l(lock_);
        return UpdateQueryStatus(status);
      }
    }
    case TStmtType::LOAD: {
      DCHECK(exec_request_.__isset.load_data_request);
      TLoadDataResp response;
      RETURN_IF_ERROR(
          frontend_->LoadData(exec_request_.load_data_request, &response));
      request_result_set_.reset(new vector<TResultRow>);
      request_result_set_->push_back(response.load_summary);
      return Status::OK;
    }
    default:
      stringstream errmsg;
      errmsg << "Unknown  exec request stmt type: " << exec_request->stmt_type;
      return Status(errmsg.str());
  }
}

Status ImpalaServer::QueryExecState::ExecQueryOrDmlRequest() {
  DCHECK(exec_request_.__isset.query_exec_request);
  TQueryExecRequest& query_exec_request = exec_request_.query_exec_request;

  // we always need at least one plan fragment
  DCHECK_GT(query_exec_request.fragments.size(), 0);

  if (query_exec_request.__isset.query_plan) {
    stringstream plan_ss;
    // Add some delimiters to make it clearer where the plan
    // begins and the profile ends
    plan_ss << "\n----------------\n"
            << query_exec_request.query_plan
            << "----------------";
    summary_profile_.AddInfoString("Plan", plan_ss.str());
  }

  // If desc_tbl is not set, query has SELECT with no FROM. In that
  // case, the query can only have a single fragment, and that fragment needs to be
  // executed by the coordinator. This check confirms that.
  // If desc_tbl is set, the query may or may not have a coordinator fragment.
  bool has_coordinator_fragment =
      query_exec_request.fragments[0].partition.type == TPartitionType::UNPARTITIONED;
  DCHECK(has_coordinator_fragment || query_exec_request.__isset.desc_tbl);

  // If the first fragment has a "limit 0", simply set EOS to true and return.
  // TODO: Remove this check if this is an INSERT. To be compatible with
  // Hive, OVERWRITE inserts must clear out target tables / static
  // partitions even if no rows are written.
  DCHECK(query_exec_request.fragments[0].__isset.plan);
  if (query_exec_request.fragments[0].plan.nodes[0].limit == 0) {
    eos_ = true;
    return Status::OK;
  }

  coord_.reset(new Coordinator(exec_env_));
  Status status = coord_->Exec(
      query_id_, &query_exec_request, exec_request_.query_options, &output_exprs_);
  {
    lock_guard<mutex> l(lock_);
    RETURN_IF_ERROR(UpdateQueryStatus(status));
  }

  profile_.AddChild(coord_->query_profile());
  return Status::OK;
}

void ImpalaServer::QueryExecState::Done() {
  end_time_ = TimestampValue::local_time_micros();
  summary_profile_.AddInfoString("End Time", end_time().DebugString());
  summary_profile_.AddInfoString("Query State", PrintQueryState(query_state_));
  query_events_->MarkEvent("Unregister query");
}

Status ImpalaServer::QueryExecState::Exec(const TMetadataOpRequest& exec_request) {
  ddl_executor_.reset(new DdlExecutor(frontend_));
  RETURN_IF_ERROR(ddl_executor_->Exec(exec_request));
  result_metadata_ = ddl_executor_->result_set_metadata();
  return Status::OK;
}

Status ImpalaServer::QueryExecState::Wait() {
  if (coord_.get() != NULL) {
    RETURN_IF_ERROR(coord_->Wait());
    RETURN_IF_ERROR(UpdateMetastore());
  }

  if (!returns_result_set()) {
    // Queries that do not return a result are finished at this point. This includes
    // DML operations and a subset of the DDL operations.
    eos_ = true;
  } else {
    // Rows are available now, so start the 'wait' timer that tracks how
    // long Impala waits for the client to fetch rows.
    client_wait_sw_.Start();
  }

  return Status::OK;
}

Status ImpalaServer::QueryExecState::FetchRows(const int32_t max_rows,
    QueryResultSet* fetched_rows) {
  // Pause the wait timer, since the client has instructed us to do
  // work on its behalf.
  client_wait_sw_.Stop();
  int64_t elapsed_time = client_wait_sw_.ElapsedTime();
  client_wait_timer_->Set(elapsed_time);

  // FetchInternal has already taken our lock_
  UpdateQueryStatus(FetchRowsInternal(max_rows, fetched_rows));

  // If all rows have been returned, no point in continuing the timer
  // to wait for the next call to FetchRows, which should never come.
  if (!eos_) client_wait_sw_.Start();
  return query_status_;
}

void ImpalaServer::QueryExecState::UpdateQueryState(QueryState::type query_state) {
  lock_guard<mutex> l(lock_);
  if (query_state_ < query_state) query_state_ = query_state;
}

Status ImpalaServer::QueryExecState::UpdateQueryStatus(const Status& status) {
  // Preserve the first non-ok status
  if (!status.ok() && query_status_.ok()) {
    query_state_ = QueryState::EXCEPTION;
    query_status_ = status;
    summary_profile_.AddInfoString("Query Status", query_status_.GetErrorMsg());
  }

  return status;
}

Status ImpalaServer::QueryExecState::FetchRowsInternal(const int32_t max_rows,
    QueryResultSet* fetched_rows) {
  DCHECK(query_state_ != QueryState::EXCEPTION);

  if (eos_) return Status::OK;

  if (ddl_executor_ != NULL || request_result_set_ != NULL) {
    // DDL / EXPLAIN / LOAD
    DCHECK(ddl_executor_ == NULL || request_result_set_ == NULL);
    query_state_ = QueryState::FINISHED;
    int num_rows = 0;
    const vector<TResultRow>& all_rows = (ddl_executor_ != NULL) ?
        ddl_executor_->result_set() : (*(request_result_set_.get()));
    // max_rows <= 0 means no limit
    while ((num_rows < max_rows || max_rows <= 0)
        && num_rows_fetched_ < all_rows.size()) {
      fetched_rows->AddOneRow(all_rows[num_rows_fetched_]);
      ++num_rows_fetched_;
      ++num_rows;
    }
    eos_ = (num_rows_fetched_ == all_rows.size());
    return Status::OK;
  }

  // List of expr values to hold evaluated rows from the query
  vector<void*> result_row;
  result_row.resize(output_exprs_.size());

  // List of scales for floating point values in result_row
  vector<int> scales;
  scales.resize(result_row.size());

  if (coord_ == NULL) {
    // query without FROM clause: we return exactly one row
    query_state_ = QueryState::FINISHED;
    eos_ = true;
    RETURN_IF_ERROR(GetRowValue(NULL, &result_row, &scales));
    return fetched_rows->AddOneRow(result_row, scales);
  }

  // query with a FROM clause
  RETURN_IF_ERROR(coord_->Wait());
  query_state_ = QueryState::FINISHED;  // results will be ready after this call
  // Fetch the next batch if we've returned the current batch entirely
  if (current_batch_ == NULL || current_batch_row_ >= current_batch_->num_rows()) {
    RETURN_IF_ERROR(FetchNextBatch());
  }
  if (current_batch_ == NULL) return Status::OK;

  {
    SCOPED_TIMER(row_materialization_timer_);
    // Convert the available rows, limited by max_rows
    int available = current_batch_->num_rows() - current_batch_row_;
    int fetched_count = available;
    // max_rows <= 0 means no limit
    if (max_rows > 0 && max_rows < available) fetched_count = max_rows;
    for (int i = 0; i < fetched_count; ++i) {
      TupleRow* row = current_batch_->GetRow(current_batch_row_);
      RETURN_IF_ERROR(GetRowValue(row, &result_row, &scales));
      RETURN_IF_ERROR(fetched_rows->AddOneRow(result_row, scales));
      ++num_rows_fetched_;
      ++current_batch_row_;
    }
  }
  return Status::OK;
}

Status ImpalaServer::QueryExecState::GetRowValue(TupleRow* row, vector<void*>* result,
                                                 vector<int>* scales) {
  DCHECK(result->size() >= output_exprs_.size());
  for (int i = 0; i < output_exprs_.size(); ++i) {
    (*result)[i] = output_exprs_[i]->GetValue(row);
    (*scales)[i] = output_exprs_[i]->output_scale();
  }
  return Status::OK;
}

void ImpalaServer::QueryExecState::Cancel() {
  // If the query is completed, no need to cancel.
  if (eos_) return;
  // we don't want multiple concurrent cancel calls to end up executing
  // Coordinator::Cancel() multiple times
  if (query_state_ == QueryState::EXCEPTION) return;
  query_state_ = QueryState::EXCEPTION;
  if (coord_.get() != NULL) coord_->Cancel();
}

Status ImpalaServer::QueryExecState::UpdateMetastore() {
  if (stmt_type() != TStmtType::DML) return Status::OK;

  DCHECK(exec_request().__isset.query_exec_request);
  TQueryExecRequest query_exec_request = exec_request().query_exec_request;
  if (!query_exec_request.__isset.finalize_params) return Status::OK;

  TFinalizeParams& finalize_params = query_exec_request.finalize_params;
  TCatalogUpdate catalog_update;
  if (!coord()->PrepareCatalogUpdate(&catalog_update)) {
    VLOG_QUERY << "No partitions altered, not updating metastore (query id: "
               << query_id() << ")";
  } else {
    // TODO: We track partitions written to, not created, which means
    // that we do more work than is necessary, because written-to
    // partitions don't always require a metastore change.
    VLOG_QUERY << "Updating metastore with " << catalog_update.created_partitions.size()
               << " altered partitions ("
               << join (catalog_update.created_partitions, ", ") << ")";

    catalog_update.target_table = finalize_params.table_name;
    catalog_update.db_name = finalize_params.table_db;
    RETURN_IF_ERROR(frontend_->UpdateMetastore(catalog_update));
  }
  return Status::OK;
}

Status ImpalaServer::QueryExecState::FetchNextBatch() {
  DCHECK(!eos_);
  DCHECK(coord_.get() != NULL);

  RETURN_IF_ERROR(coord_->GetNext(&current_batch_, coord_->runtime_state()));
  current_batch_row_ = 0;
  eos_ = current_batch_ == NULL;
  return Status::OK;
}

}
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "reconfigurable_stateserver.h"
#include "sbenv.h"
#include "remote_check.h"
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/transport.h>
#include <vespa/config/helper/configfetcher.h>
#include <thread>
#include <sstream>

#include <vespa/log/log.h>
LOG_SETUP(".slobrok.server.sbenv");

using namespace std::chrono_literals;

namespace slobrok {

namespace {

std::string
createSpec(int port)
{
    if (port == 0) {
        return std::string();
    }
    std::ostringstream str;
    str << "tcp/";
    str << vespalib::HostName::get();
    str << ":";
    str << port;
    return str.str();
}

void
discard(std::vector<std::string> &vec, const std::string & val)
{
    uint32_t i = 0;
    uint32_t size = vec.size();
    while (i < size) {
        if (vec[i] == val) {
            std::swap(vec[i], vec[size - 1]);
            vec.pop_back();
            --size;
        } else {
            ++i;
        }
    }
    LOG_ASSERT(size == vec.size());
}

class ConfigTask : public FNET_Task
{
private:
    Configurator& _configurator;

    ConfigTask(const ConfigTask &);
    ConfigTask &operator=(const ConfigTask &);
public:
    ConfigTask(FNET_Scheduler *sched, Configurator& configurator);

    ~ConfigTask();
    void PerformTask() override;
};

ConfigTask::ConfigTask(FNET_Scheduler *sched, Configurator& configurator)
    : FNET_Task(sched),
      _configurator(configurator)
{
    Schedule(1.0);
}

ConfigTask::~ConfigTask()
{
    Kill();
}

void
ConfigTask::PerformTask()
{
    Schedule(1.0);
    LOG(spam, "checking for new config");
    try {
        _configurator.poll();
    } catch (std::exception &e) {
        LOG(warning, "ConfigTask: poll failed: %s", e.what());
        Schedule(10.0);
    }
}

} // namespace slobrok::<unnamed>

SBEnv::SBEnv(const ConfigShim &shim) : SBEnv(shim, true) {}

SBEnv::SBEnv(const ConfigShim &shim, bool)
    : _transport(std::make_unique<FNET_Transport>(TransportConfig().drop_empty_buffers(true))),
      _supervisor(std::make_unique<FRT_Supervisor>(_transport.get())),
      _configShim(shim),
      _configurator(shim.factory().create(*this)),
      _shuttingDown(false),
      _useNewLogic(true),
      _partnerList(),
      _me(createSpec(_configShim.portNumber())),
      _rpcHooks(*this, _rpcsrvmap, _rpcsrvmanager),
      _remotechecktask(std::make_unique<RemoteCheck>(getSupervisor()->GetScheduler(), _rpcsrvmap, _rpcsrvmanager, _exchanger)),
      _health(),
      _metrics(_rpcHooks, *_transport),
      _components(),
      _localRpcMonitorMap(getScheduler(),
                          [this] (MappingMonitorOwner &owner) {
                              return std::make_unique<RpcMappingMonitor>(*_supervisor, owner);
                          }),
      _rpcsrvmanager(*this),
      _exchanger(*this, _rpcsrvmap),
      _rpcsrvmap()
{
    if (useNewLogic()) {
        srandom(time(nullptr) ^ getpid());
        // note: feedback loop between these two:
        _localMonitorSubscription = MapSubscription::subscribe(_consensusMap, _localRpcMonitorMap);
        _consensusSubscription = MapSubscription::subscribe(_localRpcMonitorMap.dispatcher(), _consensusMap);
        _globalHistorySubscription = MapSubscription::subscribe(_consensusMap, _globalVisibleHistory);
        _rpcHooks.initRPC(getSupervisor());
        return;
    }
    srandom(time(nullptr) ^ getpid());
    // note: feedback loop between these two:
    _localMonitorSubscription = MapSubscription::subscribe(_consensusMap, _localRpcMonitorMap);
    _consensusSubscription = MapSubscription::subscribe(_localRpcMonitorMap.dispatcher(), _consensusMap);
    _globalHistorySubscription = MapSubscription::subscribe(_rpcsrvmap.proxy(), _globalVisibleHistory);
    _rpcHooks.initRPC(getSupervisor());
}

SBEnv::~SBEnv() = default;

FNET_Scheduler *
SBEnv::getScheduler() {
    return _transport->GetScheduler();
}

void
SBEnv::shutdown()
{
    _shuttingDown = true;
    getTransport()->ShutDown(false);
}

void
SBEnv::resume()
{
    // nop
}

namespace {

vespalib::string
toString(const std::vector<std::string> & v) {
    vespalib::asciistream os;
    os << "[" << '\n';
    for (const std::string & partner : v) {
        os << "    " << partner << '\n';
    }
    os << ']';
    return os.str();
}

} // namespace <unnamed>

int
SBEnv::MainLoop()
{
    if (! getSupervisor()->Listen(_configShim.portNumber())) {
        LOG(error, "unable to listen to port %d", _configShim.portNumber());
        EV_STOPPING("slobrok", "could not listen");
        return 1;
    } else {
        LOG(config, "listening on port %d", _configShim.portNumber());
    }

    std::unique_ptr<ReconfigurableStateServer> stateServer;
    if (_configShim.enableStateServer()) {
        stateServer = std::make_unique<ReconfigurableStateServer>(_configShim.configId(), _health, _metrics, _components);
    }

    try {
        _configurator->poll();
        ConfigTask configTask(getScheduler(), *_configurator);
        LOG(debug, "slobrok: starting main event loop");
        EV_STARTED("slobrok");
        getTransport()->Main();
        LOG(debug, "slobrok: main event loop done");
    } catch (vespalib::Exception &e) {
        LOG(error, "invalid config: %s", e.what());
        EV_STOPPING("slobrok", "invalid config");
        return 1;
    } catch (std::exception &e) {
        LOG(error, "Unexpected std::exception : %s", e.what());
        EV_STOPPING("slobrok", "Unexpected std::exception");
        return 1;
    }
    EV_STOPPING("slobrok", "clean shutdown");
    return 0;
}

void
SBEnv::setup(const std::vector<std::string> &cfg)
{
    _partnerList = cfg;
    std::vector<std::string> oldList = _exchanger.getPartnerList();
    LOG(debug, "(re-)configuring. oldlist size %d, configuration list size %d",
        (int)oldList.size(),
        (int)cfg.size());
    for (uint32_t i = 0; i < cfg.size(); ++i) {
        std::string slobrok = cfg[i];
        discard(oldList, slobrok);
        if (slobrok != mySpec()) {
            OkState res = _exchanger.addPartner(slobrok);
            if (!res.ok()) {
                LOG(warning, "could not add peer %s: %s", slobrok.c_str(), res.errorMsg.c_str());
            } else {
                LOG(config, "added peer %s", slobrok.c_str());
            }
        }
    }
    for (uint32_t i = 0; i < oldList.size(); ++i) {
        OkState res = removePeer(oldList[i], oldList[i]);
        if (!res.ok()) {
            LOG(warning, "could not remove peer %s: %s", oldList[i].c_str(), res.errorMsg.c_str());
        } else {
            LOG(config, "removed peer %s", oldList[i].c_str());
        }
    }
    int64_t curGen = _configurator->getGeneration();
    vespalib::ComponentConfigProducer::Config current("slobroks", curGen, "ok");
    _components.addConfig(current);
}

OkState
SBEnv::addPeer(const std::string &name, const std::string &spec)
{
    if (name != spec) {
        return OkState(FRTE_RPC_METHOD_FAILED, "peer location brokers must have name equal to spec");
    }
    if (spec == mySpec()) {
        return OkState(FRTE_RPC_METHOD_FAILED, "cannot add my own spec as peer");
    }
    if (_partnerList.size() != 0) {
        for (const std::string & partner : _partnerList) {
            if (partner == spec) {
                return OkState(0, "already configured with peer");
            }
        }
        vespalib::string peers = toString(_partnerList);
        LOG(warning, "got addPeer with non-configured peer %s, check config consistency. configured peers = %s",
                     spec.c_str(), peers.c_str());
        _partnerList.push_back(spec);
    }
    return _exchanger.addPartner(spec);
}

OkState
SBEnv::removePeer(const std::string &name, const std::string &spec)
{
    if (name != spec) {
        return OkState(FRTE_RPC_METHOD_FAILED, "peer location brokers must have name equal to spec");
    }
    if (spec == mySpec()) {
        return OkState(FRTE_RPC_METHOD_FAILED, "cannot remove my own spec as peer");
    }
    for (const std::string & partner : _partnerList) {
        if (partner == spec) {
            return OkState(FRTE_RPC_METHOD_FAILED, "configured partner list contains peer, cannot remove");
        }
    }
    const RemoteSlobrok *partner = _exchanger.lookupPartner(name);
    if (partner == nullptr) {
        return OkState(0, "remote slobrok not a partner");
    }
    _exchanger.removePartner(name);
    return OkState(0, "done");
}

} // namespace slobrok
<commit_msg>use _exchanger.removePartner for symmetry<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "reconfigurable_stateserver.h"
#include "sbenv.h"
#include "remote_check.h"
#include <vespa/vespalib/util/host_name.h>
#include <vespa/vespalib/util/exceptions.h>
#include <vespa/vespalib/stllike/asciistream.h>
#include <vespa/fnet/frt/supervisor.h>
#include <vespa/fnet/transport.h>
#include <vespa/config/helper/configfetcher.h>
#include <thread>
#include <sstream>

#include <vespa/log/log.h>
LOG_SETUP(".slobrok.server.sbenv");

using namespace std::chrono_literals;

namespace slobrok {

namespace {

std::string
createSpec(int port)
{
    if (port == 0) {
        return std::string();
    }
    std::ostringstream str;
    str << "tcp/";
    str << vespalib::HostName::get();
    str << ":";
    str << port;
    return str.str();
}

void
discard(std::vector<std::string> &vec, const std::string & val)
{
    uint32_t i = 0;
    uint32_t size = vec.size();
    while (i < size) {
        if (vec[i] == val) {
            std::swap(vec[i], vec[size - 1]);
            vec.pop_back();
            --size;
        } else {
            ++i;
        }
    }
    LOG_ASSERT(size == vec.size());
}

class ConfigTask : public FNET_Task
{
private:
    Configurator& _configurator;

    ConfigTask(const ConfigTask &);
    ConfigTask &operator=(const ConfigTask &);
public:
    ConfigTask(FNET_Scheduler *sched, Configurator& configurator);

    ~ConfigTask();
    void PerformTask() override;
};

ConfigTask::ConfigTask(FNET_Scheduler *sched, Configurator& configurator)
    : FNET_Task(sched),
      _configurator(configurator)
{
    Schedule(1.0);
}

ConfigTask::~ConfigTask()
{
    Kill();
}

void
ConfigTask::PerformTask()
{
    Schedule(1.0);
    LOG(spam, "checking for new config");
    try {
        _configurator.poll();
    } catch (std::exception &e) {
        LOG(warning, "ConfigTask: poll failed: %s", e.what());
        Schedule(10.0);
    }
}

} // namespace slobrok::<unnamed>

SBEnv::SBEnv(const ConfigShim &shim) : SBEnv(shim, true) {}

SBEnv::SBEnv(const ConfigShim &shim, bool)
    : _transport(std::make_unique<FNET_Transport>(TransportConfig().drop_empty_buffers(true))),
      _supervisor(std::make_unique<FRT_Supervisor>(_transport.get())),
      _configShim(shim),
      _configurator(shim.factory().create(*this)),
      _shuttingDown(false),
      _useNewLogic(true),
      _partnerList(),
      _me(createSpec(_configShim.portNumber())),
      _rpcHooks(*this, _rpcsrvmap, _rpcsrvmanager),
      _remotechecktask(std::make_unique<RemoteCheck>(getSupervisor()->GetScheduler(), _rpcsrvmap, _rpcsrvmanager, _exchanger)),
      _health(),
      _metrics(_rpcHooks, *_transport),
      _components(),
      _localRpcMonitorMap(getScheduler(),
                          [this] (MappingMonitorOwner &owner) {
                              return std::make_unique<RpcMappingMonitor>(*_supervisor, owner);
                          }),
      _rpcsrvmanager(*this),
      _exchanger(*this, _rpcsrvmap),
      _rpcsrvmap()
{
    if (useNewLogic()) {
        srandom(time(nullptr) ^ getpid());
        // note: feedback loop between these two:
        _localMonitorSubscription = MapSubscription::subscribe(_consensusMap, _localRpcMonitorMap);
        _consensusSubscription = MapSubscription::subscribe(_localRpcMonitorMap.dispatcher(), _consensusMap);
        _globalHistorySubscription = MapSubscription::subscribe(_consensusMap, _globalVisibleHistory);
        _rpcHooks.initRPC(getSupervisor());
        return;
    }
    srandom(time(nullptr) ^ getpid());
    // note: feedback loop between these two:
    _localMonitorSubscription = MapSubscription::subscribe(_consensusMap, _localRpcMonitorMap);
    _consensusSubscription = MapSubscription::subscribe(_localRpcMonitorMap.dispatcher(), _consensusMap);
    _globalHistorySubscription = MapSubscription::subscribe(_rpcsrvmap.proxy(), _globalVisibleHistory);
    _rpcHooks.initRPC(getSupervisor());
}

SBEnv::~SBEnv() = default;

FNET_Scheduler *
SBEnv::getScheduler() {
    return _transport->GetScheduler();
}

void
SBEnv::shutdown()
{
    _shuttingDown = true;
    getTransport()->ShutDown(false);
}

void
SBEnv::resume()
{
    // nop
}

namespace {

vespalib::string
toString(const std::vector<std::string> & v) {
    vespalib::asciistream os;
    os << "[" << '\n';
    for (const std::string & partner : v) {
        os << "    " << partner << '\n';
    }
    os << ']';
    return os.str();
}

} // namespace <unnamed>

int
SBEnv::MainLoop()
{
    if (! getSupervisor()->Listen(_configShim.portNumber())) {
        LOG(error, "unable to listen to port %d", _configShim.portNumber());
        EV_STOPPING("slobrok", "could not listen");
        return 1;
    } else {
        LOG(config, "listening on port %d", _configShim.portNumber());
    }

    std::unique_ptr<ReconfigurableStateServer> stateServer;
    if (_configShim.enableStateServer()) {
        stateServer = std::make_unique<ReconfigurableStateServer>(_configShim.configId(), _health, _metrics, _components);
    }

    try {
        _configurator->poll();
        ConfigTask configTask(getScheduler(), *_configurator);
        LOG(debug, "slobrok: starting main event loop");
        EV_STARTED("slobrok");
        getTransport()->Main();
        LOG(debug, "slobrok: main event loop done");
    } catch (vespalib::Exception &e) {
        LOG(error, "invalid config: %s", e.what());
        EV_STOPPING("slobrok", "invalid config");
        return 1;
    } catch (std::exception &e) {
        LOG(error, "Unexpected std::exception : %s", e.what());
        EV_STOPPING("slobrok", "Unexpected std::exception");
        return 1;
    }
    EV_STOPPING("slobrok", "clean shutdown");
    return 0;
}

void
SBEnv::setup(const std::vector<std::string> &cfg)
{
    _partnerList = cfg;
    std::vector<std::string> oldList = _exchanger.getPartnerList();
    LOG(debug, "(re-)configuring. oldlist size %d, configuration list size %d",
        (int)oldList.size(),
        (int)cfg.size());
    for (uint32_t i = 0; i < cfg.size(); ++i) {
        std::string slobrok = cfg[i];
        discard(oldList, slobrok);
        if (slobrok != mySpec()) {
            OkState res = _exchanger.addPartner(slobrok);
            if (!res.ok()) {
                LOG(warning, "could not add peer %s: %s", slobrok.c_str(), res.errorMsg.c_str());
            } else {
                LOG(config, "added peer %s", slobrok.c_str());
            }
        }
    }
    for (uint32_t i = 0; i < oldList.size(); ++i) {
        _exchanger.removePartner(oldList[i]);
        LOG(config, "removed peer %s", oldList[i].c_str());
    }
    int64_t curGen = _configurator->getGeneration();
    vespalib::ComponentConfigProducer::Config current("slobroks", curGen, "ok");
    _components.addConfig(current);
}

OkState
SBEnv::addPeer(const std::string &name, const std::string &spec)
{
    if (name != spec) {
        return OkState(FRTE_RPC_METHOD_FAILED, "peer location brokers must have name equal to spec");
    }
    if (spec == mySpec()) {
        return OkState(FRTE_RPC_METHOD_FAILED, "cannot add my own spec as peer");
    }
    if (_partnerList.size() != 0) {
        for (const std::string & partner : _partnerList) {
            if (partner == spec) {
                return OkState(0, "already configured with peer");
            }
        }
        vespalib::string peers = toString(_partnerList);
        LOG(warning, "got addPeer with non-configured peer %s, check config consistency. configured peers = %s",
                     spec.c_str(), peers.c_str());
        _partnerList.push_back(spec);
    }
    return _exchanger.addPartner(spec);
}

OkState
SBEnv::removePeer(const std::string &name, const std::string &spec)
{
    if (name != spec) {
        return OkState(FRTE_RPC_METHOD_FAILED, "peer location brokers must have name equal to spec");
    }
    if (spec == mySpec()) {
        return OkState(FRTE_RPC_METHOD_FAILED, "cannot remove my own spec as peer");
    }
    for (const std::string & partner : _partnerList) {
        if (partner == spec) {
            return OkState(FRTE_RPC_METHOD_FAILED, "configured partner list contains peer, cannot remove");
        }
    }
    const RemoteSlobrok *partner = _exchanger.lookupPartner(name);
    if (partner == nullptr) {
        return OkState(0, "remote slobrok not a partner");
    }
    _exchanger.removePartner(name);
    return OkState(0, "done");
}

} // namespace slobrok
<|endoftext|>


<commit_before>#include "KinectStreamsMat.h"

CKinectStreamsMat::CKinectStreamsMat()
{
	_sensor = nullptr;
	_depth_reader = nullptr;
	_depth_source = nullptr;
	_color_reader = nullptr;
	_color_source = nullptr;
}

CKinectStreamsMat::~CKinectStreamsMat()
{
	SafeRelease(_depth_source);
	SafeRelease(_depth_reader);
	SafeRelease(_color_source);
	SafeRelease(_color_reader);
	if (_sensor) {
		_sensor->Close();
	}
	SafeRelease(_sensor);
}

cv:: Mat CKinectStreamsMat::getDepthFrame()
{
	HRESULT hr = E_FAIL;
	IDepthFrame* frame = nullptr;
	cv::Mat depthImage;
	IFrameDescription* frame_desc = nullptr;
	hr = _depth_reader->AcquireLatestFrame(&frame);
	if (SUCCEEDED(hr)) {
		hr = frame->get_FrameDescription(&frame_desc);
		if (SUCCEEDED(hr)) {
			int frameWidth = 0, frameHeight = 0;
			hr = frame_desc->get_Width(&frameWidth);
			if (SUCCEEDED(hr))
			{
				hr = frame_desc->get_Height(&frameHeight);
			}
			if (SUCCEEDED(hr)) {
				const int imgSize = frameWidth*frameHeight;
				UINT16* pixelData = new UINT16[imgSize];
				hr = frame->CopyFrameDataToArray(imgSize,pixelData);
				if (SUCCEEDED(hr)) {
					depthImage = cv::Mat(frameHeight,frameWidth, CV_8U);
					for (int i = 0; i < imgSize; i++) {
						UINT16 depth = pixelData[i];
						depthImage.at<UINT8>(i) = depth & 0xffff;
					}
				}
			}
		}
		SafeRelease(frame_desc);
		SafeRelease(frame);
	}
	return depthImage;
}

 cv::Mat CKinectStreamsMat::getColorFrame()
 {
	 HRESULT hr = E_FAIL;
	 IColorFrame* frame = NULL;
	 IFrameDescription* frameDesc;
	cv::Mat colorImage;
	 hr = _color_reader->AcquireLatestFrame(&frame);
	 if (SUCCEEDED(hr)) {
		 hr = frame->get_FrameDescription(&frameDesc);
		 if (SUCCEEDED(hr)) {
			 int frameWidth = 0, frameHeight = 0;
			 hr = frameDesc->get_Width(&frameWidth);
			 if (SUCCEEDED(hr)) {
				 hr = frameDesc->get_Height(&frameHeight);
			 }
			 if (SUCCEEDED(hr)) {
				 const int imgSize = frameWidth*frameHeight * 4; //4 Channels(BGRA)
				 BYTE* frameData = new BYTE[imgSize];
				 hr = frame->CopyConvertedFrameDataToArray(imgSize, frameData, ColorImageFormat_Bgra);
				 if (SUCCEEDED(hr)) {
					 colorImage = cv::Mat(frameHeight, frameWidth, CV_8UC4, reinterpret_cast<void*>(frameData));
				 }
			 }
		 }
		 SafeRelease(frameDesc);
		 SafeRelease(frame);
	 }
	 return colorImage;
 }

HRESULT CKinectStreamsMat::initSensor()
{
	HRESULT hr = GetDefaultKinectSensor(&_sensor);
	if (FAILED(hr)) {
		return hr;
	}

	if (_sensor) {
		hr = _sensor->Open();
		HRESULT hr2 = hr;

		if (SUCCEEDED(hr)) {
			hr = _sensor->get_DepthFrameSource(&_depth_source);
		}

		if (SUCCEEDED(hr)) {
			hr = _depth_source->OpenReader(&_depth_reader);
		}

		if (SUCCEEDED(hr2)) {
			hr2 = _sensor->get_ColorFrameSource(&_color_source);
		}

		if (SUCCEEDED(hr2)) {
			hr2 = _color_source->OpenReader(&_color_reader);
		}

		hr = hr2;
	}

	return hr;
}
<commit_msg>Update KinectStreamsMat.cpp<commit_after>/*Copyright (C) 2016, Shubham Batra (https://www.github.com/batrashubham)
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 "KinectStreamsMat.h"

CKinectStreamsMat::CKinectStreamsMat()
{
	_sensor = nullptr;
	_depth_reader = nullptr;
	_depth_source = nullptr;
	_color_reader = nullptr;
	_color_source = nullptr;
}

CKinectStreamsMat::~CKinectStreamsMat()
{
	SafeRelease(_depth_source);
	SafeRelease(_depth_reader);
	SafeRelease(_color_source);
	SafeRelease(_color_reader);
	if (_sensor) {
		_sensor->Close();
	}
	SafeRelease(_sensor);
}

cv:: Mat CKinectStreamsMat::getDepthFrame()
{
	HRESULT hr = E_FAIL;
	IDepthFrame* frame = nullptr;
	cv::Mat depthImage;
	IFrameDescription* frame_desc = nullptr;
	hr = _depth_reader->AcquireLatestFrame(&frame);
	if (SUCCEEDED(hr)) {
		hr = frame->get_FrameDescription(&frame_desc);
		if (SUCCEEDED(hr)) {
			int frameWidth = 0, frameHeight = 0;
			hr = frame_desc->get_Width(&frameWidth);
			if (SUCCEEDED(hr))
			{
				hr = frame_desc->get_Height(&frameHeight);
			}
			if (SUCCEEDED(hr)) {
				const int imgSize = frameWidth*frameHeight;
				UINT16* pixelData = new UINT16[imgSize];
				hr = frame->CopyFrameDataToArray(imgSize,pixelData);
				if (SUCCEEDED(hr)) {
					depthImage = cv::Mat(frameHeight,frameWidth, CV_8U);
					for (int i = 0; i < imgSize; i++) {
						UINT16 depth = pixelData[i];
						depthImage.at<UINT8>(i) = depth & 0xffff;
					}
				}
			}
		}
		SafeRelease(frame_desc);
		SafeRelease(frame);
	}
	return depthImage;
}

 cv::Mat CKinectStreamsMat::getColorFrame()
 {
	 HRESULT hr = E_FAIL;
	 IColorFrame* frame = NULL;
	 IFrameDescription* frameDesc;
	cv::Mat colorImage;
	 hr = _color_reader->AcquireLatestFrame(&frame);
	 if (SUCCEEDED(hr)) {
		 hr = frame->get_FrameDescription(&frameDesc);
		 if (SUCCEEDED(hr)) {
			 int frameWidth = 0, frameHeight = 0;
			 hr = frameDesc->get_Width(&frameWidth);
			 if (SUCCEEDED(hr)) {
				 hr = frameDesc->get_Height(&frameHeight);
			 }
			 if (SUCCEEDED(hr)) {
				 const int imgSize = frameWidth*frameHeight * 4; //4 Channels(BGRA)
				 BYTE* frameData = new BYTE[imgSize];
				 hr = frame->CopyConvertedFrameDataToArray(imgSize, frameData, ColorImageFormat_Bgra);
				 if (SUCCEEDED(hr)) {
					 colorImage = cv::Mat(frameHeight, frameWidth, CV_8UC4, reinterpret_cast<void*>(frameData));
				 }
			 }
		 }
		 SafeRelease(frameDesc);
		 SafeRelease(frame);
	 }
	 return colorImage;
 }

HRESULT CKinectStreamsMat::initSensor()
{
	HRESULT hr = GetDefaultKinectSensor(&_sensor);
	if (FAILED(hr)) {
		return hr;
	}

	if (_sensor) {
		hr = _sensor->Open();
		HRESULT hr2 = hr;

		if (SUCCEEDED(hr)) {
			hr = _sensor->get_DepthFrameSource(&_depth_source);
		}

		if (SUCCEEDED(hr)) {
			hr = _depth_source->OpenReader(&_depth_reader);
		}

		if (SUCCEEDED(hr2)) {
			hr2 = _sensor->get_ColorFrameSource(&_color_source);
		}

		if (SUCCEEDED(hr2)) {
			hr2 = _color_source->OpenReader(&_color_reader);
		}

		hr = hr2;
	}

	return hr;
}
<|endoftext|>


<commit_before>/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** MJPEGVideoSource.cpp
**
** V4L2 RTSP streamer
**
** MJPEG Source for RTSP server
**
** -------------------------------------------------------------------------*/

#include "MJPEGVideoSource.h"

void MJPEGVideoSource::afterGettingFrame(unsigned frameSize,unsigned numTruncatedBytes,struct timeval presentationTime,unsigned durationInMicroseconds)
{
	int headerSize = 0;
	fFrameSize = 0;

	unsigned int i = 0;
	while ( (i<frameSize) && (headerSize==0) ) {
	    // SOF
	    if ( ((i+11) < frameSize)  && (fTo[i] == 0xFF) && (fTo[i+1] == 0xC0) ) {
		int length = (fTo[i+2]<<8)|(fTo[i+3]);
		LOG(DEBUG) << "SOF length:" << length;

		m_height = (fTo[i+5]<<5)|(fTo[i+6]>>3);
		m_width  = (fTo[i+7]<<5)|(fTo[i+8]>>3);

		int hv_subsampling = fTo[i+11];
		if (hv_subsampling == 0x21 ) {
		    m_type = 0; // JPEG 4:2:2
		} else if (hv_subsampling == 0x22 ) {
		    m_type = 1; // JPEG 4:2:0
		} else {
		    LOG(NOTICE) << "not managed sampling:0x" << std::hex << hv_subsampling;
		    m_type = 255;
		}

		int precision = fTo[i+4];
		LOG(INFO) << "width:" << (int)(m_width<<3) << " height:" << (int)(m_height<<3) << " type:"<< (int)m_type << " precision:" << precision;

		i+=length+2;
	    }
	    // DQT
	    else if ( ( (i+5+64) < frameSize)  && (fTo[i] == 0xFF) && (fTo[i+1] == 0xDB)) {
		int length = (fTo[i+2]<<8)|(fTo[i+3]);
		LOG(DEBUG) << "DQT length:" << length;

		unsigned int precision = (fTo[i+4]&0xf0)<<4;
		unsigned int quantIdx  = fTo[i+4]&0x0f;
		unsigned int quantSize = length-3;
		if (quantSize*quantIdx+quantSize <= sizeof(m_qTable)) {
		    memcpy(m_qTable + quantSize*quantIdx, fTo + i + 5, quantSize);
		    LOG(NOTICE) << "Quantization table idx:" << quantIdx << " precision:" << precision << " size:" << quantSize << " total size:" << m_qTableSize;
		    if (quantSize*quantIdx+quantSize > m_qTableSize) {
			m_qTableSize = quantSize*quantIdx+quantSize;
		    }
		}

		i+=length+2;
	    }
	    // SOS
	    else if ( ((i+1) < frameSize) && (fTo[i] == 0xFF) && (fTo[i+1] == 0xDA) ) {
		int length = (fTo[i+2]<<8)|(fTo[i+3]);
		LOG(DEBUG) << "SOS length:" << length;

		headerSize = i+length+2;
	    } else {
		i++;
	    }
	}

	if (headerSize != 0) {
	    LOG(DEBUG) << "headerSize:" << headerSize;
	    fFrameSize = frameSize - headerSize;
	    memmove( fTo, fTo + headerSize, fFrameSize );
	} else {
	    LOG(NOTICE) << "Bad header => dropping frame";
	}

	fNumTruncatedBytes = numTruncatedBytes;
	fPresentationTime = presentationTime;
	fDurationInMicroseconds = durationInMicroseconds;
	afterGetting(this);
}

u_int8_t const* MJPEGVideoSource::quantizationTables( u_int8_t& precision, u_int16_t& length )
{
	length = 0;
	precision = 0;
	if (m_qTableSize > 0)
	{
		length = m_qTableSize;
		precision = m_precision;
	}
	return m_qTable;
}
<commit_msg>fix JPEG quantization size<commit_after>/* ---------------------------------------------------------------------------
** This software is in the public domain, furnished "as is", without technical
** support, and with no warranty, express or implied, as to its usefulness for
** any purpose.
**
** MJPEGVideoSource.cpp
**
** V4L2 RTSP streamer
**
** MJPEG Source for RTSP server
**
** -------------------------------------------------------------------------*/

#include "MJPEGVideoSource.h"

void MJPEGVideoSource::afterGettingFrame(unsigned frameSize,unsigned numTruncatedBytes,struct timeval presentationTime,unsigned durationInMicroseconds)
{
	int headerSize = 0;
	fFrameSize = 0;

	unsigned int i = 0;
	while ( (i<frameSize) && (headerSize==0) ) {
	    // SOF
	    if ( ((i+11) < frameSize)  && (fTo[i] == 0xFF) && (fTo[i+1] == 0xC0) ) {
		int length = (fTo[i+2]<<8)|(fTo[i+3]);
		LOG(DEBUG) << "SOF length:" << length;

		m_height = (fTo[i+5]<<5)|(fTo[i+6]>>3);
		m_width  = (fTo[i+7]<<5)|(fTo[i+8]>>3);

		int hv_subsampling = fTo[i+11];
		if (hv_subsampling == 0x21 ) {
		    m_type = 0; // JPEG 4:2:2
		} else if (hv_subsampling == 0x22 ) {
		    m_type = 1; // JPEG 4:2:0
		} else {
		    LOG(NOTICE) << "not managed sampling:0x" << std::hex << hv_subsampling;
		    m_type = 255;
		}

		int precision = fTo[i+4];
		LOG(INFO) << "width:" << (int)(m_width<<3) << " height:" << (int)(m_height<<3) << " type:"<< (int)m_type << " precision:" << precision;

		i+=length+2;
	    }
	    // DQT
	    else if ( ( (i+5+64) < frameSize)  && (fTo[i] == 0xFF) && (fTo[i+1] == 0xDB)) {
		int length = (fTo[i+2]<<8)|(fTo[i+3]);
		LOG(DEBUG) << "DQT length:" << length;

		unsigned int precision = (fTo[i+4]&0xf0)<<4;
		unsigned int quantIdx  = fTo[i+4]&0x0f;
		unsigned int quantSize = length-4;
		if (quantSize*quantIdx+quantSize <= sizeof(m_qTable)) {
		    memcpy(m_qTable + quantSize*quantIdx, fTo + i + 5, quantSize);
		    LOG(DEBUG) << "Quantization table idx:" << quantIdx << " precision:" << precision << " size:" << quantSize << " total size:" << m_qTableSize;
		    if (quantSize*quantIdx+quantSize > m_qTableSize) {
			m_qTableSize = quantSize*quantIdx+quantSize;
		    }
		}

		i+=length+2;
	    }
	    // SOS
	    else if ( ((i+1) < frameSize) && (fTo[i] == 0xFF) && (fTo[i+1] == 0xDA) ) {
		int length = (fTo[i+2]<<8)|(fTo[i+3]);
		LOG(DEBUG) << "SOS length:" << length;

		headerSize = i+length+2;
	    } else {
		i++;
	    }
	}

	if (headerSize != 0) {
	    LOG(DEBUG) << "headerSize:" << headerSize;
	    fFrameSize = frameSize - headerSize;
	    memmove( fTo, fTo + headerSize, fFrameSize );
	} else {
	    LOG(NOTICE) << "Bad header => dropping frame";
	}

	fNumTruncatedBytes = numTruncatedBytes;
	fPresentationTime = presentationTime;
	fDurationInMicroseconds = durationInMicroseconds;
	afterGetting(this);
}

u_int8_t const* MJPEGVideoSource::quantizationTables( u_int8_t& precision, u_int16_t& length )
{
	length = 0;
	precision = 0;
	if (m_qTableSize > 0)
	{
		length = m_qTableSize;
		precision = m_precision;
	}
	return m_qTable;
}
<|endoftext|>


<commit_before>/*
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
 */

#include "Common/config.h"
#include "RtpReceiver.h"

#define AV_RB16(x)                           \
    ((((const uint8_t*)(x))[0] << 8) |          \
      ((const uint8_t*)(x))[1])

#define RTP_MAX_SIZE (10 * 1024)

namespace mediakit {

RtpReceiver::RtpReceiver() {
    int index = 0;
    for (auto &sortor : _rtp_sortor) {
        sortor.setOnSort([this, index](uint16_t seq, RtpPacket::Ptr &packet) {
            onRtpSorted(packet, index);
        });
        ++index;
    }
}
RtpReceiver::~RtpReceiver() {}

bool RtpReceiver::handleOneRtp(int track_index, TrackType type, int samplerate, unsigned char *rtp_raw_ptr, unsigned int rtp_raw_len) {
    if (rtp_raw_len < 12) {
        WarnL << "rtp包太小:" << rtp_raw_len;
        return false;
    }

    uint8_t padding = 0;
    if (rtp_raw_ptr[0] & 0x20) {
        //获取padding大小
        padding = rtp_raw_ptr[rtp_raw_len - 1];
        //移除padding flag
        rtp_raw_ptr[0] &= ~0x20;
        //移除padding字节
        rtp_raw_len -= padding;
    }

    auto rtp_ptr = _rtp_pool.obtain();
    auto &rtp = *rtp_ptr;

    rtp.type = type;
    rtp.interleaved = 2 * type;
    rtp.mark = rtp_raw_ptr[1] >> 7;
    rtp.PT = rtp_raw_ptr[1] & 0x7F;

    //序列号,内存对齐
    memcpy(&rtp.sequence, rtp_raw_ptr + 2, 2);
    rtp.sequence = ntohs(rtp.sequence);

    //时间戳,内存对齐
    memcpy(&rtp.timeStamp, rtp_raw_ptr + 4, 4);
    rtp.timeStamp = ntohl(rtp.timeStamp);

    if (!samplerate) {
        //无法把时间戳转换成毫秒
        return false;
    }
    //时间戳转换成毫秒
    rtp.timeStamp = rtp.timeStamp * 1000LL / samplerate;

    //ssrc,内存对齐
    memcpy(&rtp.ssrc, rtp_raw_ptr + 8, 4);
    rtp.ssrc = ntohl(rtp.ssrc);

    if (_ssrc[track_index] != rtp.ssrc) {
        if (_ssrc[track_index] == 0) {
            //保存SSRC至track对象
            _ssrc[track_index] = rtp.ssrc;
        } else {
            //ssrc错误
            WarnL << "ssrc错误:" << rtp.ssrc << " != " << _ssrc[track_index];
            if (_ssrc_err_count[track_index]++ > 10) {
                //ssrc切换后清除老数据
                WarnL << "ssrc更换:" << _ssrc[track_index] << " -> " << rtp.ssrc;
                _rtp_sortor[track_index].clear();
                _ssrc[track_index] = rtp.ssrc;
            }
            return false;
        }
    }

    //ssrc匹配正确，不匹配计数清零
    _ssrc_err_count[track_index] = 0;

    //获取rtp中媒体数据偏移量
    rtp.offset = 12 + 4;
    int csrc = rtp_raw_ptr[0] & 0x0f;
    int ext = rtp_raw_ptr[0] & 0x10;
    rtp.offset += 4 * csrc;
    if (ext && rtp_raw_len >= rtp.offset) {
        /* calculate the header extension length (stored as number of 32-bit words) */
        ext = (AV_RB16(rtp_raw_ptr + rtp.offset - 2) + 1) << 2;
        rtp.offset += ext;
    }

    if (rtp_raw_len + 4 <= rtp.offset) {
        WarnL << "无有效负载的rtp包:" << rtp_raw_len << " <= " << (int) rtp.offset;
        return false;
    }

    if (rtp_raw_len > RTP_MAX_SIZE) {
        WarnL << "超大的rtp包:" << rtp_raw_len << " > " << RTP_MAX_SIZE;
        return false;
    }

    //设置rtp负载长度
    rtp.setCapacity(rtp_raw_len + 4);
    rtp.setSize(rtp_raw_len + 4);
    uint8_t *payload_ptr = (uint8_t *) rtp.data();
    payload_ptr[0] = '$';
    payload_ptr[1] = rtp.interleaved;
    payload_ptr[2] = rtp_raw_len >> 8;
    payload_ptr[3] = (rtp_raw_len & 0x00FF);
    //拷贝rtp负载
    memcpy(payload_ptr + 4, rtp_raw_ptr, rtp_raw_len);

    //排序rtp
    auto seq = rtp_ptr->sequence;
    _rtp_sortor[track_index].sortPacket(seq, std::move(rtp_ptr));
    return true;
}

void RtpReceiver::clear() {
    CLEAR_ARR(_ssrc);
    CLEAR_ARR(_ssrc_err_count);
    for (auto &sortor : _rtp_sortor) {
        sortor.clear();
    }
}

void RtpReceiver::setPoolSize(int size) {
    _rtp_pool.setSize(size);
}

int RtpReceiver::getJitterSize(int track_index){
    return _rtp_sortor[track_index].getJitterSize();
}

int RtpReceiver::getCycleCount(int track_index){
    return _rtp_sortor[track_index].getCycleCount();
}

}//namespace mediakit
<commit_msg>校验rtp是否合法<commit_after>/*
 * Copyright (c) 2016 The ZLMediaKit project authors. All Rights Reserved.
 *
 * This file is part of ZLMediaKit(https://github.com/xiongziliang/ZLMediaKit).
 *
 * Use of this source code is governed by MIT license that can be found in the
 * LICENSE file in the root of the source tree. All contributing project authors
 * may be found in the AUTHORS file in the root of the source tree.
 */

#include "Common/config.h"
#include "RtpReceiver.h"

#define AV_RB16(x)                           \
    ((((const uint8_t*)(x))[0] << 8) |          \
      ((const uint8_t*)(x))[1])

#define RTP_MAX_SIZE (10 * 1024)

namespace mediakit {

RtpReceiver::RtpReceiver() {
    int index = 0;
    for (auto &sortor : _rtp_sortor) {
        sortor.setOnSort([this, index](uint16_t seq, RtpPacket::Ptr &packet) {
            onRtpSorted(packet, index);
        });
        ++index;
    }
}
RtpReceiver::~RtpReceiver() {}

bool RtpReceiver::handleOneRtp(int track_index, TrackType type, int samplerate, unsigned char *rtp_raw_ptr, unsigned int rtp_raw_len) {
    if (rtp_raw_len < 12) {
        WarnL << "rtp包太小:" << rtp_raw_len;
        return false;
    }

    uint32_t version = rtp_raw_ptr[0] >> 6;
    uint8_t padding = 0;
    uint8_t ext = rtp_raw_ptr[0] & 0x10;
    uint8_t csrc = rtp_raw_ptr[0] & 0x0f;

    if (rtp_raw_ptr[0] & 0x20) {
        //获取padding大小
        padding = rtp_raw_ptr[rtp_raw_len - 1];
        //移除padding flag
        rtp_raw_ptr[0] &= ~0x20;
        //移除padding字节
        rtp_raw_len -= padding;
    }

    if (version != 2) {
        throw std::invalid_argument("非法的rtp，version != 2");
    }

    auto rtp_ptr = _rtp_pool.obtain();
    auto &rtp = *rtp_ptr;

    rtp.type = type;
    rtp.interleaved = 2 * type;
    rtp.mark = rtp_raw_ptr[1] >> 7;
    rtp.PT = rtp_raw_ptr[1] & 0x7F;

    //序列号,内存对齐
    memcpy(&rtp.sequence, rtp_raw_ptr + 2, 2);
    rtp.sequence = ntohs(rtp.sequence);

    //时间戳,内存对齐
    memcpy(&rtp.timeStamp, rtp_raw_ptr + 4, 4);
    rtp.timeStamp = ntohl(rtp.timeStamp);

    if (!samplerate) {
        //无法把时间戳转换成毫秒
        return false;
    }
    //时间戳转换成毫秒
    rtp.timeStamp = rtp.timeStamp * 1000LL / samplerate;

    //ssrc,内存对齐
    memcpy(&rtp.ssrc, rtp_raw_ptr + 8, 4);
    rtp.ssrc = ntohl(rtp.ssrc);

    if (_ssrc[track_index] != rtp.ssrc) {
        if (_ssrc[track_index] == 0) {
            //保存SSRC至track对象
            _ssrc[track_index] = rtp.ssrc;
        } else {
            //ssrc错误
            WarnL << "ssrc错误:" << rtp.ssrc << " != " << _ssrc[track_index];
            if (_ssrc_err_count[track_index]++ > 10) {
                //ssrc切换后清除老数据
                WarnL << "ssrc更换:" << _ssrc[track_index] << " -> " << rtp.ssrc;
                _rtp_sortor[track_index].clear();
                _ssrc[track_index] = rtp.ssrc;
            }
            return false;
        }
    }

    //ssrc匹配正确，不匹配计数清零
    _ssrc_err_count[track_index] = 0;

    //获取rtp中媒体数据偏移量
    rtp.offset = 12 + 4;
    rtp.offset += 4 * csrc;
    if (ext && rtp_raw_len >= rtp.offset) {
        /* calculate the header extension length (stored as number of 32-bit words) */
        ext = (AV_RB16(rtp_raw_ptr + rtp.offset - 2) + 1) << 2;
        rtp.offset += ext;
    }

    if (rtp_raw_len + 4 <= rtp.offset) {
        WarnL << "无有效负载的rtp包:" << rtp_raw_len << " <= " << (int) rtp.offset;
        return false;
    }

    if (rtp_raw_len > RTP_MAX_SIZE) {
        WarnL << "超大的rtp包:" << rtp_raw_len << " > " << RTP_MAX_SIZE;
        return false;
    }

    //设置rtp负载长度
    rtp.setCapacity(rtp_raw_len + 4);
    rtp.setSize(rtp_raw_len + 4);
    uint8_t *payload_ptr = (uint8_t *) rtp.data();
    payload_ptr[0] = '$';
    payload_ptr[1] = rtp.interleaved;
    payload_ptr[2] = rtp_raw_len >> 8;
    payload_ptr[3] = (rtp_raw_len & 0x00FF);
    //拷贝rtp负载
    memcpy(payload_ptr + 4, rtp_raw_ptr, rtp_raw_len);

    //排序rtp
    auto seq = rtp_ptr->sequence;
    _rtp_sortor[track_index].sortPacket(seq, std::move(rtp_ptr));
    return true;
}

void RtpReceiver::clear() {
    CLEAR_ARR(_ssrc);
    CLEAR_ARR(_ssrc_err_count);
    for (auto &sortor : _rtp_sortor) {
        sortor.clear();
    }
}

void RtpReceiver::setPoolSize(int size) {
    _rtp_pool.setSize(size);
}

int RtpReceiver::getJitterSize(int track_index){
    return _rtp_sortor[track_index].getJitterSize();
}

int RtpReceiver::getCycleCount(int track_index){
    return _rtp_sortor[track_index].getCycleCount();
}

}//namespace mediakit
<|endoftext|>


<commit_before>//===-- ValueObjectConstResultImpl.cpp ---------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Core/ValueObjectConstResultImpl.h"

#include "lldb/Core/ValueObjectChild.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectConstResultChild.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ValueObjectList.h"

#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/Variable.h"

#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"

using namespace lldb;
using namespace lldb_private;

// this macro enables a simpler implementation for some method calls in this object that relies only upon
// ValueObject knowing how to set the address type of its children correctly. the alternative implementation
// relies on being able to create a target copy of the frozen object, which makes it less bug-prone but less
// efficient as well. once we are confident the faster implementation is bug-free, this macro (and the slower
// implementations) can go
#define TRIVIAL_IMPL 1

ValueObjectConstResultImpl::ValueObjectConstResultImpl (ValueObject* valobj,
                                                        lldb::addr_t live_address) :
    m_impl_backend(valobj),
    m_live_address(live_address),
    m_live_address_type(eAddressTypeLoad),
    m_load_addr_backend(),
    m_address_of_backend()
{
}

lldb::ValueObjectSP
ValueObjectConstResultImpl::DerefOnTarget()
{
    if (m_load_addr_backend.get() == NULL)
    {
        lldb::addr_t tgt_address = m_impl_backend->GetPointerValue();
        ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
        m_load_addr_backend = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
                                                              m_impl_backend->GetClangType(),
                                                              m_impl_backend->GetName(),
                                                              tgt_address,
                                                              eAddressTypeLoad,
                                                              exe_ctx.GetAddressByteSize());
    }
    return m_load_addr_backend;
}

lldb::ValueObjectSP
ValueObjectConstResultImpl::Dereference (Error &error)
{
    if (m_impl_backend == NULL)
        return lldb::ValueObjectSP();

#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
    return m_impl_backend->ValueObject::Dereference(error);
#else
    m_impl_backend->UpdateValueIfNeeded(false);

    if (NeedsDerefOnTarget())
        return DerefOnTarget()->Dereference(error);
    else
        return m_impl_backend->ValueObject::Dereference(error);
#endif
}

ValueObject *
ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
{
    if (m_impl_backend == NULL)
        return NULL;

    m_impl_backend->UpdateValueIfNeeded(false);

    ValueObjectConstResultChild *valobj = NULL;

    bool omit_empty_base_classes = true;
    bool ignore_array_bounds = synthetic_array_member;
    std::string child_name_str;
    uint32_t child_byte_size = 0;
    int32_t child_byte_offset = 0;
    uint32_t child_bitfield_bit_size = 0;
    uint32_t child_bitfield_bit_offset = 0;
    bool child_is_base_class = false;
    bool child_is_deref_of_parent = false;

    const bool transparent_pointers = synthetic_array_member == false;
    ClangASTType clang_type = m_impl_backend->GetClangType();
    ClangASTType child_clang_type;

    ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());

    child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
                                                            idx,
                                                            transparent_pointers,
                                                            omit_empty_base_classes,
                                                            ignore_array_bounds,
                                                            child_name_str,
                                                            child_byte_size,
                                                            child_byte_offset,
                                                            child_bitfield_bit_size,
                                                            child_bitfield_bit_offset,
                                                            child_is_base_class,
                                                            child_is_deref_of_parent,
                                                            m_impl_backend);
    if (child_clang_type && child_byte_size)
    {
        if (synthetic_index)
            child_byte_offset += child_byte_size * synthetic_index;

        ConstString child_name;
        if (!child_name_str.empty())
            child_name.SetCString (child_name_str.c_str());

        valobj = new ValueObjectConstResultChild (*m_impl_backend,
                                                  child_clang_type,
                                                  child_name,
                                                  child_byte_size,
                                                  child_byte_offset,
                                                  child_bitfield_bit_size,
                                                  child_bitfield_bit_offset,
                                                  child_is_base_class,
                                                  child_is_deref_of_parent);
        if (m_live_address != LLDB_INVALID_ADDRESS)
            valobj->m_impl.SetLiveAddress(m_live_address+child_byte_offset);
    }

    return valobj;
}

lldb::ValueObjectSP
ValueObjectConstResultImpl::GetSyntheticChildAtOffset (uint32_t offset, const ClangASTType& type, bool can_create)
{
    if (m_impl_backend == NULL)
        return lldb::ValueObjectSP();

#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
    return m_impl_backend->ValueObject::GetSyntheticChildAtOffset(offset, type, can_create);
#else
    m_impl_backend->UpdateValueIfNeeded(false);

    if (NeedsDerefOnTarget())
        return DerefOnTarget()->GetSyntheticChildAtOffset(offset, type, can_create);
    else
        return m_impl_backend->ValueObject::GetSyntheticChildAtOffset(offset, type, can_create);
#endif
}

lldb::ValueObjectSP
ValueObjectConstResultImpl::AddressOf (Error &error)
{
    if (m_address_of_backend.get() != NULL)
        return m_address_of_backend;

    if (m_impl_backend == NULL)
        return lldb::ValueObjectSP();
    if (m_live_address != LLDB_INVALID_ADDRESS)
    {
        ClangASTType clang_type(m_impl_backend->GetClangType());

        lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&m_live_address,sizeof(lldb::addr_t)));

        std::string new_name("&");
        new_name.append(m_impl_backend->GetName().AsCString(""));
        ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
        m_address_of_backend = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
                                                               clang_type.GetPointerType(),
                                                               ConstString(new_name.c_str()),
                                                               buffer,
                                                               lldb::endian::InlHostByteOrder(),
                                                               exe_ctx.GetAddressByteSize());

        m_address_of_backend->GetValue().SetValueType(Value::eValueTypeScalar);
        m_address_of_backend->GetValue().GetScalar() = m_live_address;

        return m_address_of_backend;
    }
    else
        return m_impl_backend->ValueObject::AddressOf(error);
}

lldb::addr_t
ValueObjectConstResultImpl::GetAddressOf (bool scalar_is_load_address,
                                          AddressType *address_type)
{

    if (m_impl_backend == NULL)
        return 0;

    if (m_live_address == LLDB_INVALID_ADDRESS)
    {
        return m_impl_backend->ValueObject::GetAddressOf (scalar_is_load_address,
                                                          address_type);
    }

    if (address_type)
        *address_type = m_live_address_type;

    return m_live_address;
}

size_t
ValueObjectConstResultImpl::GetPointeeData (DataExtractor& data,
                                            uint32_t item_idx,
                                            uint32_t item_count)
{
    if (m_impl_backend == NULL)
        return 0;
#if defined (TRIVIAL_IMPL) && TRIVIAL_IMPL == 1
    return m_impl_backend->ValueObject::GetPointeeData(data, item_idx, item_count);
#else
    m_impl_backend->UpdateValueIfNeeded(false);

    if (NeedsDerefOnTarget() && m_impl_backend->IsPointerType())
        return DerefOnTarget()->GetPointeeData(data, item_idx, item_count);
    else
        return m_impl_backend->ValueObject::GetPointeeData(data, item_idx, item_count);
#endif
}
<commit_msg>The so-called "trivial implementation" has been with us for a few years now. It's probably safe to assume it works.. so remove the #if stuff<commit_after>//===-- ValueObjectConstResultImpl.cpp ---------------------------*- C++ -*-===//
//
//                     The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//

#include "lldb/Core/ValueObjectConstResultImpl.h"

#include "lldb/Core/ValueObjectChild.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectConstResultChild.h"
#include "lldb/Core/ValueObjectMemory.h"
#include "lldb/Core/DataExtractor.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/ValueObjectList.h"

#include "lldb/Symbol/ClangASTType.h"
#include "lldb/Symbol/ObjectFile.h"
#include "lldb/Symbol/SymbolContext.h"
#include "lldb/Symbol/Type.h"
#include "lldb/Symbol/Variable.h"

#include "lldb/Target/ExecutionContext.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"

using namespace lldb;
using namespace lldb_private;

ValueObjectConstResultImpl::ValueObjectConstResultImpl (ValueObject* valobj,
                                                        lldb::addr_t live_address) :
    m_impl_backend(valobj),
    m_live_address(live_address),
    m_live_address_type(eAddressTypeLoad),
    m_load_addr_backend(),
    m_address_of_backend()
{
}

lldb::ValueObjectSP
ValueObjectConstResultImpl::DerefOnTarget()
{
    if (m_load_addr_backend.get() == NULL)
    {
        lldb::addr_t tgt_address = m_impl_backend->GetPointerValue();
        ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
        m_load_addr_backend = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
                                                              m_impl_backend->GetClangType(),
                                                              m_impl_backend->GetName(),
                                                              tgt_address,
                                                              eAddressTypeLoad,
                                                              exe_ctx.GetAddressByteSize());
    }
    return m_load_addr_backend;
}

lldb::ValueObjectSP
ValueObjectConstResultImpl::Dereference (Error &error)
{
    if (m_impl_backend == NULL)
        return lldb::ValueObjectSP();

    return m_impl_backend->ValueObject::Dereference(error);
}

ValueObject *
ValueObjectConstResultImpl::CreateChildAtIndex (size_t idx, bool synthetic_array_member, int32_t synthetic_index)
{
    if (m_impl_backend == NULL)
        return NULL;

    m_impl_backend->UpdateValueIfNeeded(false);

    ValueObjectConstResultChild *valobj = NULL;

    bool omit_empty_base_classes = true;
    bool ignore_array_bounds = synthetic_array_member;
    std::string child_name_str;
    uint32_t child_byte_size = 0;
    int32_t child_byte_offset = 0;
    uint32_t child_bitfield_bit_size = 0;
    uint32_t child_bitfield_bit_offset = 0;
    bool child_is_base_class = false;
    bool child_is_deref_of_parent = false;

    const bool transparent_pointers = synthetic_array_member == false;
    ClangASTType clang_type = m_impl_backend->GetClangType();
    ClangASTType child_clang_type;

    ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());

    child_clang_type = clang_type.GetChildClangTypeAtIndex (&exe_ctx,
                                                            idx,
                                                            transparent_pointers,
                                                            omit_empty_base_classes,
                                                            ignore_array_bounds,
                                                            child_name_str,
                                                            child_byte_size,
                                                            child_byte_offset,
                                                            child_bitfield_bit_size,
                                                            child_bitfield_bit_offset,
                                                            child_is_base_class,
                                                            child_is_deref_of_parent,
                                                            m_impl_backend);
    if (child_clang_type && child_byte_size)
    {
        if (synthetic_index)
            child_byte_offset += child_byte_size * synthetic_index;

        ConstString child_name;
        if (!child_name_str.empty())
            child_name.SetCString (child_name_str.c_str());

        valobj = new ValueObjectConstResultChild (*m_impl_backend,
                                                  child_clang_type,
                                                  child_name,
                                                  child_byte_size,
                                                  child_byte_offset,
                                                  child_bitfield_bit_size,
                                                  child_bitfield_bit_offset,
                                                  child_is_base_class,
                                                  child_is_deref_of_parent);
        if (m_live_address != LLDB_INVALID_ADDRESS)
            valobj->m_impl.SetLiveAddress(m_live_address+child_byte_offset);
    }

    return valobj;
}

lldb::ValueObjectSP
ValueObjectConstResultImpl::GetSyntheticChildAtOffset (uint32_t offset, const ClangASTType& type, bool can_create)
{
    if (m_impl_backend == NULL)
        return lldb::ValueObjectSP();

    return m_impl_backend->ValueObject::GetSyntheticChildAtOffset(offset, type, can_create);
}

lldb::ValueObjectSP
ValueObjectConstResultImpl::AddressOf (Error &error)
{
    if (m_address_of_backend.get() != NULL)
        return m_address_of_backend;

    if (m_impl_backend == NULL)
        return lldb::ValueObjectSP();
    if (m_live_address != LLDB_INVALID_ADDRESS)
    {
        ClangASTType clang_type(m_impl_backend->GetClangType());

        lldb::DataBufferSP buffer(new lldb_private::DataBufferHeap(&m_live_address,sizeof(lldb::addr_t)));

        std::string new_name("&");
        new_name.append(m_impl_backend->GetName().AsCString(""));
        ExecutionContext exe_ctx (m_impl_backend->GetExecutionContextRef());
        m_address_of_backend = ValueObjectConstResult::Create (exe_ctx.GetBestExecutionContextScope(),
                                                               clang_type.GetPointerType(),
                                                               ConstString(new_name.c_str()),
                                                               buffer,
                                                               lldb::endian::InlHostByteOrder(),
                                                               exe_ctx.GetAddressByteSize());

        m_address_of_backend->GetValue().SetValueType(Value::eValueTypeScalar);
        m_address_of_backend->GetValue().GetScalar() = m_live_address;

        return m_address_of_backend;
    }
    else
        return m_impl_backend->ValueObject::AddressOf(error);
}

lldb::addr_t
ValueObjectConstResultImpl::GetAddressOf (bool scalar_is_load_address,
                                          AddressType *address_type)
{

    if (m_impl_backend == NULL)
        return 0;

    if (m_live_address == LLDB_INVALID_ADDRESS)
    {
        return m_impl_backend->ValueObject::GetAddressOf (scalar_is_load_address,
                                                          address_type);
    }

    if (address_type)
        *address_type = m_live_address_type;

    return m_live_address;
}

size_t
ValueObjectConstResultImpl::GetPointeeData (DataExtractor& data,
                                            uint32_t item_idx,
                                            uint32_t item_count)
{
    if (m_impl_backend == NULL)
        return 0;
    return m_impl_backend->ValueObject::GetPointeeData(data, item_idx, item_count);
}
<|endoftext|>