<commit_before>// Copyright 2012 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 "statestore/state-store-subscriber.h"

#include <sstream>
#include <utility>

#include <boost/algorithm/string/join.hpp>
#include <boost/foreach.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/shared_mutex.hpp>

#include "common/logging.h"
#include "common/status.h"
#include "statestore/failure-detector.h"
#include "gen-cpp/StateStoreService_types.h"
#include "util/thrift-util.h"

using namespace std;
using namespace boost;
using namespace boost::posix_time;
using namespace ::apache::thrift;
using namespace ::apache::thrift::transport;

DEFINE_int32(statestore_subscriber_timeout_seconds, 10, "The amount of time (in seconds)"
     " that may elapse before the connection with the state-store is considered lost.");

namespace impala {

// Used to identify the statestore in the failure detector
const string STATE_STORE_ID = "STATESTORE";

// Duration, in ms, to sleep between attempts to reconnect to the
// state-store after a failure.
const int32_t SLEEP_INTERVAL_MS = 5000;

typedef ClientConnection<StateStoreServiceClient> StateStoreConnection;

// Proxy class for the subscriber heartbeat thrift API, which
// translates RPCs into method calls on the local subscriber object.
class StateStoreSubscriberThriftIf : public StateStoreSubscriberIf {
 public:
  StateStoreSubscriberThriftIf(StateStoreSubscriber* subscriber)
      : subscriber_(subscriber) { DCHECK(subscriber != NULL); }
  virtual void UpdateState(TUpdateStateResponse& response,
                           const TUpdateStateRequest& params) {
    subscriber_->UpdateState(params.topic_deltas, &response.topic_updates);
    Status::OK.ToThrift(&response.status);
  }

 private:
  StateStoreSubscriber* subscriber_;
};

StateStoreSubscriber::StateStoreSubscriber(const std::string& subscriber_id,
    const TNetworkAddress& heartbeat_address, const TNetworkAddress& state_store_address,
    Metrics* metrics)
    : subscriber_id_(subscriber_id), heartbeat_address_(heartbeat_address),
      state_store_address_(state_store_address),
      thrift_iface_(new StateStoreSubscriberThriftIf(this)),
      failure_detector_(new TimeoutFailureDetector(
          seconds(FLAGS_statestore_subscriber_timeout_seconds),
          seconds(FLAGS_statestore_subscriber_timeout_seconds / 2))),
      is_registered_(false),
      client_cache_(new StateStoreClientCache()) {
  connected_to_statestore_metric_ =
      metrics->CreateAndRegisterPrimitiveMetric("statestore-subscriber.connected", false);
  last_recovery_time_metric_ =
      metrics->CreateAndRegisterPrimitiveMetric(
          "statestore-subscriber.last-recovery-time", 0.0);
  heartbeat_interval_metric_ =
      metrics->RegisterMetric(
          new StatsMetric<double>("statestore-subscriber.heartbeat-interval-time", 0.0));
  heartbeat_duration_metric_ =
      metrics->RegisterMetric(
          new StatsMetric<double>("statestore-subscriber.heartbeat-duration", 0.0));
  client_cache_->InitMetrics(metrics, "statestore-subscriber.statestore");
}

Status StateStoreSubscriber::AddTopic(const StateStore::TopicId& topic_id,
    bool is_transient, const UpdateCallback& callback) {
  lock_guard<mutex> l(lock_);
  if (is_registered_) return Status("Subscriber already started, can't add new topic");
  update_callbacks_[topic_id].push_back(callback);
  topic_registrations_[topic_id] = is_transient;
  return Status::OK;
}

Status StateStoreSubscriber::Register() {
  Status client_status;
  StateStoreConnection client(client_cache_.get(), state_store_address_, &client_status);
  RETURN_IF_ERROR(client_status);

  TRegisterSubscriberRequest request;
  request.topic_registrations.reserve(update_callbacks_.size());
  BOOST_FOREACH(const UpdateCallbacks::value_type& topic, update_callbacks_) {
    TTopicRegistration thrift_topic;
    thrift_topic.topic_name = topic.first;
    thrift_topic.is_transient = topic_registrations_[topic.first];
    request.topic_registrations.push_back(thrift_topic);
  }

  request.subscriber_location = heartbeat_address_;
  request.subscriber_id = subscriber_id_;
  TRegisterSubscriberResponse response;
  client->RegisterSubscriber(response, request);
  Status status = Status(response.status);
  if (status.ok()) connected_to_statestore_metric_->Update(true);
  heartbeat_interval_timer_.Start();
  return status;
}

Status StateStoreSubscriber::Start() {
  lock_guard<mutex> l(lock_);
  LOG(INFO) << "Starting subscriber";

  // Backend must be started before registration
  shared_ptr<TProcessor> processor(new StateStoreSubscriberProcessor(thrift_iface_));
  heartbeat_server_.reset(new ThriftServer("StateStoreSubscriber", processor,
                                           heartbeat_address_.port, NULL, 5));
  heartbeat_server_->Start();
  Status status = Register();
  if (status.ok()) is_registered_ = true;
  recovery_mode_thread_.reset(
      new thread(&StateStoreSubscriber::RecoveryModeChecker, this));

  return status;
}

void StateStoreSubscriber::RecoveryModeChecker() {
  failure_detector_->UpdateHeartbeat(STATE_STORE_ID, true);

  // Every few seconds, wake up and check if the failure detector has determined
  // that the state-store has failed from our perspective. If so, enter recovery
  // mode and try to reconnect, followed by reregistering all subscriptions.
  while (true) {
    if (failure_detector_->GetPeerState(STATE_STORE_ID) == FailureDetector::FAILED) {
      // When entering recovery mode, the class-wide lock_ is taken to
      // ensure mutual exclusion with any operations in flight.
      lock_guard<mutex> l(lock_);
      MonotonicStopWatch recovery_timer;
      recovery_timer.Start();
      connected_to_statestore_metric_->Update(false);
      LOG(INFO) << subscriber_id_
                << ": Connection with state-store lost, entering recovery mode";
      while (true) {
        LOG(INFO) << "Trying to register...";
        Status status = Register();
        if (status.ok()) {
          LOG(INFO) << "Reconnected to state-store. Exiting recovery mode";
          // Make sure to update failure detector so that we don't
          // immediately fail on the next loop while we're waiting for
          // heartbeats to resume.
          failure_detector_->UpdateHeartbeat(STATE_STORE_ID, true);
          // Break out of enclosing while (true) to top of outer-scope loop.
          break;
        } else {
          // Don't exit recovery mode, continue
          LOG(WARNING) << "Failed to re-register with state-store: "
                       << status.GetErrorMsg();
          usleep(SLEEP_INTERVAL_MS * 1000);
        }
        last_recovery_time_metric_->Update(
            recovery_timer.ElapsedTime() / (1000.0 * 1000.0 * 1000.0));
      }
      // When we're successful in re-registering, we don't do anything
      // to re-send our updates to the state-store. It is the
      // responsibility of individual clients to post missing updates
      // back to the state-store. This saves a lot of complexity where
      // we would otherwise have to cache updates here.

      last_recovery_time_metric_->Update(
          recovery_timer.ElapsedTime() / (1000.0 * 1000.0 * 1000.0));
    }

    usleep(SLEEP_INTERVAL_MS * 1000);
  }
}

void StateStoreSubscriber::UpdateState(const TopicDeltaMap& topic_deltas,
    vector<TTopicUpdate>* topic_updates) {
  failure_detector_->UpdateHeartbeat(STATE_STORE_ID, true);

  // We don't want to block here because this is an RPC, and delaying
  // the return causes the state-store to delay sending the next batch
  // of heartbeats. The only time that lock_ will be taken once
  // UpdateState might be called is in RecoveryModeChecker; if we're
  // in recovery mode we don't want to process the update.
  try_mutex::scoped_try_lock l(lock_);
  if (l) {
    // Only record heartbeats received when not in recovery mode
    heartbeat_interval_metric_->Update(
        heartbeat_interval_timer_.Reset() / (1000.0 * 1000.0 * 1000.0));
    MonotonicStopWatch sw;
    sw.Start();
    BOOST_FOREACH(const UpdateCallbacks::value_type& callbacks, update_callbacks_) {
      BOOST_FOREACH(const UpdateCallback& callback, callbacks.second) {
        // TODO: Consider filtering the topics to only send registered topics to callbacks
        callback(topic_deltas, topic_updates);
      }
    }
    sw.Stop();
    heartbeat_duration_metric_->Update(sw.ElapsedTime() / (1000.0 * 1000.0 * 1000.0));
  } else {
    VLOG(1) << "In recovery mode, ignoring update.";
  }
}

}
<commit_msg>IMPALA-312 add try/catch for state store rpc<commit_after>// Copyright 2012 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 "statestore/state-store-subscriber.h"

#include <sstream>
#include <utility>

#include <boost/algorithm/string/join.hpp>
#include <boost/foreach.hpp>
#include <boost/date_time/posix_time/posix_time.hpp>
#include <boost/thread/shared_mutex.hpp>

#include "common/logging.h"
#include "common/status.h"
#include "statestore/failure-detector.h"
#include "gen-cpp/StateStoreService_types.h"
#include "util/thrift-util.h"

using namespace std;
using namespace boost;
using namespace boost::posix_time;
using namespace ::apache::thrift;
using namespace ::apache::thrift::transport;

DEFINE_int32(statestore_subscriber_timeout_seconds, 10, "The amount of time (in seconds)"
     " that may elapse before the connection with the state-store is considered lost.");

namespace impala {

// Used to identify the statestore in the failure detector
const string STATE_STORE_ID = "STATESTORE";

// Duration, in ms, to sleep between attempts to reconnect to the
// state-store after a failure.
const int32_t SLEEP_INTERVAL_MS = 5000;

typedef ClientConnection<StateStoreServiceClient> StateStoreConnection;

// Proxy class for the subscriber heartbeat thrift API, which
// translates RPCs into method calls on the local subscriber object.
class StateStoreSubscriberThriftIf : public StateStoreSubscriberIf {
 public:
  StateStoreSubscriberThriftIf(StateStoreSubscriber* subscriber)
      : subscriber_(subscriber) { DCHECK(subscriber != NULL); }
  virtual void UpdateState(TUpdateStateResponse& response,
                           const TUpdateStateRequest& params) {
    subscriber_->UpdateState(params.topic_deltas, &response.topic_updates);
    Status::OK.ToThrift(&response.status);
  }

 private:
  StateStoreSubscriber* subscriber_;
};

StateStoreSubscriber::StateStoreSubscriber(const std::string& subscriber_id,
    const TNetworkAddress& heartbeat_address, const TNetworkAddress& state_store_address,
    Metrics* metrics)
    : subscriber_id_(subscriber_id), heartbeat_address_(heartbeat_address),
      state_store_address_(state_store_address),
      thrift_iface_(new StateStoreSubscriberThriftIf(this)),
      failure_detector_(new TimeoutFailureDetector(
          seconds(FLAGS_statestore_subscriber_timeout_seconds),
          seconds(FLAGS_statestore_subscriber_timeout_seconds / 2))),
      is_registered_(false),
      client_cache_(new StateStoreClientCache()) {
  connected_to_statestore_metric_ =
      metrics->CreateAndRegisterPrimitiveMetric("statestore-subscriber.connected", false);
  last_recovery_time_metric_ =
      metrics->CreateAndRegisterPrimitiveMetric(
          "statestore-subscriber.last-recovery-time", 0.0);
  heartbeat_interval_metric_ =
      metrics->RegisterMetric(
          new StatsMetric<double>("statestore-subscriber.heartbeat-interval-time", 0.0));
  heartbeat_duration_metric_ =
      metrics->RegisterMetric(
          new StatsMetric<double>("statestore-subscriber.heartbeat-duration", 0.0));
  client_cache_->InitMetrics(metrics, "statestore-subscriber.statestore");
}

Status StateStoreSubscriber::AddTopic(const StateStore::TopicId& topic_id,
    bool is_transient, const UpdateCallback& callback) {
  lock_guard<mutex> l(lock_);
  if (is_registered_) return Status("Subscriber already started, can't add new topic");
  update_callbacks_[topic_id].push_back(callback);
  topic_registrations_[topic_id] = is_transient;
  return Status::OK;
}

Status StateStoreSubscriber::Register() {
  Status client_status;
  StateStoreConnection client(client_cache_.get(), state_store_address_, &client_status);
  RETURN_IF_ERROR(client_status);

  TRegisterSubscriberRequest request;
  request.topic_registrations.reserve(update_callbacks_.size());
  BOOST_FOREACH(const UpdateCallbacks::value_type& topic, update_callbacks_) {
    TTopicRegistration thrift_topic;
    thrift_topic.topic_name = topic.first;
    thrift_topic.is_transient = topic_registrations_[topic.first];
    request.topic_registrations.push_back(thrift_topic);
  }

  request.subscriber_location = heartbeat_address_;
  request.subscriber_id = subscriber_id_;
  TRegisterSubscriberResponse response;
  try {
    client->RegisterSubscriber(response, request);
  } catch (apache::thrift::transport::TTransportException& e) {
    // Client may have been closed due to a failure
    RETURN_IF_ERROR(client.Reopen());
    try {
      client->RegisterSubscriber(response, request);
    } catch (apache::thrift::transport::TTransportException& e) {
      return Status(e.what());
    }
  }
  Status status = Status(response.status);
  if (status.ok()) connected_to_statestore_metric_->Update(true);
  heartbeat_interval_timer_.Start();
  return status;
}

Status StateStoreSubscriber::Start() {
  lock_guard<mutex> l(lock_);
  LOG(INFO) << "Starting subscriber";

  // Backend must be started before registration
  shared_ptr<TProcessor> processor(new StateStoreSubscriberProcessor(thrift_iface_));
  heartbeat_server_.reset(new ThriftServer("StateStoreSubscriber", processor,
                                           heartbeat_address_.port, NULL, 5));
  heartbeat_server_->Start();
  Status status = Register();
  if (status.ok()) is_registered_ = true;
  recovery_mode_thread_.reset(
      new thread(&StateStoreSubscriber::RecoveryModeChecker, this));

  return status;
}

void StateStoreSubscriber::RecoveryModeChecker() {
  failure_detector_->UpdateHeartbeat(STATE_STORE_ID, true);

  // Every few seconds, wake up and check if the failure detector has determined
  // that the state-store has failed from our perspective. If so, enter recovery
  // mode and try to reconnect, followed by reregistering all subscriptions.
  while (true) {
    if (failure_detector_->GetPeerState(STATE_STORE_ID) == FailureDetector::FAILED) {
      // When entering recovery mode, the class-wide lock_ is taken to
      // ensure mutual exclusion with any operations in flight.
      lock_guard<mutex> l(lock_);
      MonotonicStopWatch recovery_timer;
      recovery_timer.Start();
      connected_to_statestore_metric_->Update(false);
      LOG(INFO) << subscriber_id_
                << ": Connection with state-store lost, entering recovery mode";
      while (true) {
        LOG(INFO) << "Trying to register...";
        Status status = Register();
        if (status.ok()) {
          LOG(INFO) << "Reconnected to state-store. Exiting recovery mode";
          // Make sure to update failure detector so that we don't
          // immediately fail on the next loop while we're waiting for
          // heartbeats to resume.
          failure_detector_->UpdateHeartbeat(STATE_STORE_ID, true);
          // Break out of enclosing while (true) to top of outer-scope loop.
          break;
        } else {
          // Don't exit recovery mode, continue
          LOG(WARNING) << "Failed to re-register with state-store: "
                       << status.GetErrorMsg();
          usleep(SLEEP_INTERVAL_MS * 1000);
        }
        last_recovery_time_metric_->Update(
            recovery_timer.ElapsedTime() / (1000.0 * 1000.0 * 1000.0));
      }
      // When we're successful in re-registering, we don't do anything
      // to re-send our updates to the state-store. It is the
      // responsibility of individual clients to post missing updates
      // back to the state-store. This saves a lot of complexity where
      // we would otherwise have to cache updates here.

      last_recovery_time_metric_->Update(
          recovery_timer.ElapsedTime() / (1000.0 * 1000.0 * 1000.0));
    }

    usleep(SLEEP_INTERVAL_MS * 1000);
  }
}

void StateStoreSubscriber::UpdateState(const TopicDeltaMap& topic_deltas,
    vector<TTopicUpdate>* topic_updates) {
  failure_detector_->UpdateHeartbeat(STATE_STORE_ID, true);

  // We don't want to block here because this is an RPC, and delaying
  // the return causes the state-store to delay sending the next batch
  // of heartbeats. The only time that lock_ will be taken once
  // UpdateState might be called is in RecoveryModeChecker; if we're
  // in recovery mode we don't want to process the update.
  try_mutex::scoped_try_lock l(lock_);
  if (l) {
    // Only record heartbeats received when not in recovery mode
    heartbeat_interval_metric_->Update(
        heartbeat_interval_timer_.Reset() / (1000.0 * 1000.0 * 1000.0));
    MonotonicStopWatch sw;
    sw.Start();
    BOOST_FOREACH(const UpdateCallbacks::value_type& callbacks, update_callbacks_) {
      BOOST_FOREACH(const UpdateCallback& callback, callbacks.second) {
        // TODO: Consider filtering the topics to only send registered topics to callbacks
        callback(topic_deltas, topic_updates);
      }
    }
    sw.Stop();
    heartbeat_duration_metric_->Update(sw.ElapsedTime() / (1000.0 * 1000.0 * 1000.0));
  } else {
    VLOG(1) << "In recovery mode, ignoring update.";
  }
}

}
<|endoftext|>


<commit_before>// For conditions of distribution and use, see copyright notice in license.txt

/*! \mainpage

    \section intro_sec Introduction

    Welcome to realXtend viewer source code documentation.

    First of all you might want to get to know coding conventions of the
    realXtend viewer. A document containing the guidelines can be found
    from the documentation directory.

    The viewer is divided into several different projects and namespaces.

    - The Core contains functionality common to all projects in the viewer.
    - The Foundation is the framework around which the viewer is build.
    - Several modules that create the functionality of the viewer with the
      help of the framework.

    \section install_sec Compiling the Viewer

    See readme.txt for information about compiling the viewer.

    \section license License

    For conditions of distribution and use, see copyright notice in license.txt

*/

#include "CoreStdIncludes.h"
#include "Core.h"
#include "Foundation.h"

#if defined(_MSC_VER) && defined(_DMEMORYLEAKS)
// for reporting memory leaks upon debug exit
#include <crtdbg.h>
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
// For generating minidump
#  include <dbghelp.h>
#  include <shellapi.h>
#  include <shlobj.h>
#pragma warning( push )
#pragma warning( disable : 4996 )
#  include <strsafe.h>
#pragma warning( pop )
#endif

int run(void);

#if defined(_MSC_VER) && defined(_DMEMDUMP)
int generateDump(EXCEPTION_POINTERS* pExceptionPointers);
#endif

int main(int argc, char **argv)
{
    int retVal = EXIT_SUCCESS;

    // set debug flag for memory leaks
#   if defined(_MSC_VER) && defined(_DMEMORYLEAKS)
    int tmpDbgFlag;
    tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
    tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;
    _CrtSetDbgFlag(tmpDbgFlag);
#   endif

#   if defined(_MSC_VER) && defined(_DMEMDUMP)
    __try
    {
#   endif

    retVal = run();

#   if defined(_MSC_VER) && defined(_DMEMDUMP)
    }
    __except(generateDump(GetExceptionInformation()))
    {
    }
#  endif

   return retVal;
}

int run(void)
{
    int retVal = EXIT_SUCCESS;

    // Create application object
    Foundation::Framework fw;
    try
    {
        fw.Go();
    }
    catch ( std::exception& e )
    {
        Foundation::Platform::Message("An exception has occurred!", e.what());
        retVal = EXIT_FAILURE;
    }

    return retVal;
}

#if defined(_MSC_VER) && defined(_DMEMDUMP)
int generateDump(EXCEPTION_POINTERS* pExceptionPointers)
{
    BOOL bMiniDumpSuccessful;
    WCHAR szPath[MAX_PATH];
    WCHAR szFileName[MAX_PATH];
    WCHAR* szAppName = L"RexNG Viewer";
    WCHAR* szVersion = L"alpha";
    DWORD dwBufferSize = MAX_PATH;
    HANDLE hDumpFile;
    SYSTEMTIME stLocalTime;
    MINIDUMP_EXCEPTION_INFORMATION ExpParam;

    GetLocalTime( &stLocalTime );
    GetTempPathW( dwBufferSize, szPath );

    StringCchPrintf( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );
    CreateDirectoryW( szFileName, NULL );
    StringCchPrintf( szFileName, MAX_PATH, L"%s%s\\%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
               szPath, szAppName, szVersion,
               stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
               stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
               GetCurrentProcessId(), GetCurrentThreadId());

    hDumpFile = CreateFileW(szFileName, GENERIC_READ|GENERIC_WRITE,
                FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

    ExpParam.ThreadId = GetCurrentThreadId();
    ExpParam.ExceptionPointers = pExceptionPointers;
    ExpParam.ClientPointers = TRUE;

    bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
                    hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);

    std::wstring message(L"Program ");
    message += szAppName;
    message += L" encountered an unexpected error.\n\nCrashdump was saved to location:\n";
    message += szFileName;

    if (bMiniDumpSuccessful)
        Foundation::Platform::Message(L"Minidump generated!", message);
    else
        Foundation::Platform::Message(szAppName, L"Un unexpected error was encountred while generating minidump!");

    return EXCEPTION_EXECUTE_HANDLER;
}
#endif

<commit_msg>Modified exception handling in debug mode.<commit_after>// For conditions of distribution and use, see copyright notice in license.txt

/*! \mainpage

    \section intro_sec Introduction

    Welcome to realXtend viewer source code documentation.

    First of all you might want to get to know coding conventions of the
    realXtend viewer. A document containing the guidelines can be found
    from the documentation directory.

    The viewer is divided into several different projects and namespaces.

    - The Core contains functionality common to all projects in the viewer.
    - The Foundation is the framework around which the viewer is build.
    - Several modules that create the functionality of the viewer with the
      help of the framework.

    \section install_sec Compiling the Viewer

    See readme.txt for information about compiling the viewer.

    \section license License

    For conditions of distribution and use, see copyright notice in license.txt

*/

#include "CoreStdIncludes.h"
#include "Core.h"
#include "Foundation.h"

#if defined(_MSC_VER) && defined(_DMEMORYLEAKS)
// for reporting memory leaks upon debug exit
#include <crtdbg.h>
#endif

#if defined(_MSC_VER) && defined(_DMEMDUMP)
// For generating minidump
#  include <dbghelp.h>
#  include <shellapi.h>
#  include <shlobj.h>
#pragma warning( push )
#pragma warning( disable : 4996 )
#  include <strsafe.h>
#pragma warning( pop )
#endif

int run(void);

#if defined(_MSC_VER) && defined(_DMEMDUMP)
int generateDump(EXCEPTION_POINTERS* pExceptionPointers);
#endif

int main(int argc, char **argv)
{
    int retVal = EXIT_SUCCESS;

    // set debug flag for memory leaks
#   if defined(_MSC_VER) && defined(_DMEMORYLEAKS)
    int tmpDbgFlag;
    tmpDbgFlag = _CrtSetDbgFlag(_CRTDBG_REPORT_FLAG);
    tmpDbgFlag |= _CRTDBG_LEAK_CHECK_DF;
    _CrtSetDbgFlag(tmpDbgFlag);
#   endif

#   if defined(_MSC_VER) && defined(_DMEMDUMP)
    __try
    {
#   endif

    retVal = run();

#   if defined(_MSC_VER) && defined(_DMEMDUMP)
    }
    __except(generateDump(GetExceptionInformation()))
    {
    }
#  endif

   return retVal;
}

int run(void)
{
    int retVal = EXIT_SUCCESS;

    // Create application object
    Foundation::Framework fw;

    try
    {
        fw.Go();
    }
    catch ( std::exception& e )
    {
#if defined(_DEBUG) && defined(_MSC_VER)
        // handling exception in debug mode. Feel free to modify if this doesn't work for you.
        UNREFERENCED_PARAM(e);
        __debugbreak();
#else
        Foundation::Platform::Message("An exception has occurred!", e.what());
        retVal = EXIT_FAILURE;
#endif
    }

    return retVal;
}

#if defined(_MSC_VER) && defined(_DMEMDUMP)
int generateDump(EXCEPTION_POINTERS* pExceptionPointers)
{
    BOOL bMiniDumpSuccessful;
    WCHAR szPath[MAX_PATH];
    WCHAR szFileName[MAX_PATH];
    WCHAR* szAppName = L"RexNG Viewer";
    WCHAR* szVersion = L"alpha";
    DWORD dwBufferSize = MAX_PATH;
    HANDLE hDumpFile;
    SYSTEMTIME stLocalTime;
    MINIDUMP_EXCEPTION_INFORMATION ExpParam;

    GetLocalTime( &stLocalTime );
    GetTempPathW( dwBufferSize, szPath );

    StringCchPrintf( szFileName, MAX_PATH, L"%s%s", szPath, szAppName );
    CreateDirectoryW( szFileName, NULL );
    StringCchPrintf( szFileName, MAX_PATH, L"%s%s\\%s-%04d%02d%02d-%02d%02d%02d-%ld-%ld.dmp",
               szPath, szAppName, szVersion,
               stLocalTime.wYear, stLocalTime.wMonth, stLocalTime.wDay,
               stLocalTime.wHour, stLocalTime.wMinute, stLocalTime.wSecond,
               GetCurrentProcessId(), GetCurrentThreadId());

    hDumpFile = CreateFileW(szFileName, GENERIC_READ|GENERIC_WRITE,
                FILE_SHARE_WRITE|FILE_SHARE_READ, 0, CREATE_ALWAYS, 0, 0);

    ExpParam.ThreadId = GetCurrentThreadId();
    ExpParam.ExceptionPointers = pExceptionPointers;
    ExpParam.ClientPointers = TRUE;

    bMiniDumpSuccessful = MiniDumpWriteDump(GetCurrentProcess(), GetCurrentProcessId(),
                    hDumpFile, MiniDumpWithDataSegs, &ExpParam, NULL, NULL);

    std::wstring message(L"Program ");
    message += szAppName;
    message += L" encountered an unexpected error.\n\nCrashdump was saved to location:\n";
    message += szFileName;

    if (bMiniDumpSuccessful)
        Foundation::Platform::Message(L"Minidump generated!", message);
    else
        Foundation::Platform::Message(szAppName, L"Un unexpected error was encountred while generating minidump!");

    return EXCEPTION_EXECUTE_HANDLER;
}
#endif

<|endoftext|>


<commit_before>/*********************************************************************************
* Copyright (c) 2013 David D. Marshall <ddmarsha@calpoly.edu>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    David D. Marshall - initial code and implementation
********************************************************************************/

#ifndef eli_mutil_nls_newton_raphson_system_method_hpp
#define eli_mutil_nls_newton_raphson_system_method_hpp

#include "eli/code_eli.hpp"

#include "eli/mutil/nls/iterative_system_root_base_constrained.hpp"

namespace eli
{
  namespace mutil
  {
    namespace nls
    {
      // Small systems where N__<=4
      template<typename data__, size_t N__, size_t NSOL__=1>
      class newton_raphson_system_method : public iterative_system_root_base_constrained<data__, N__, NSOL__>
      {
        public:
          static const int hit_constraint = 101;

        public:
          newton_raphson_system_method()
          : iterative_system_root_base_constrained<data__, N__, NSOL__>()
          {
            x0.setConstant(static_cast<data__>(0));
          }

          newton_raphson_system_method(const newton_raphson_system_method<data__, N__, NSOL__> &nrm)
          : iterative_system_root_base_constrained<data__, N__, NSOL__>(nrm), x0(nrm.x0)
          {
          }

          ~newton_raphson_system_method()
          {
          }

          void set_initial_guess(const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &xg)
          {
            x0=xg;
          }

          const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix & get_initial_guess() const
          {
            return x0;
          }

          template<typename f__, typename g__>
          int find_root(typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &root, const f__ &fun, const g__ &fprime, const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &f0) const
          {
            typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix dx, x(x0), fx(fun(x0)), eval1, eval2, eval3;
            typename iterative_system_root_base<data__, N__, NSOL__>::jacobian_matrix fpx(fprime(x0));
            data__ abs_tol_norm, rel_tol_norm, abs_x_norm, rel_x_norm;
            typename iterative_root_base<data__>::iteration_type count;

            // calculate the function evaluated at the initial location
            eval1=fx-f0;
            abs_tol_norm=this->calculate_norm(eval1);
            eval2=(fx-f0).array()/f0.array();
            eval2.setConstant(1);
            rel_tol_norm=this->calculate_norm(eval2);
            if (this->test_converged(0, rel_tol_norm, abs_tol_norm, 0, 0))
            {
              root=x;
              return this->converged;
            }

            bool all_zero(false);
            abs_x_norm=0;
            rel_x_norm=0;
            count=0;
            while (!this->test_converged(count, rel_tol_norm, abs_tol_norm, rel_x_norm, abs_x_norm) && !all_zero)
            {
  // FIX: Don't have any easy (efficient) way of determining if matrix in invertible
  //            if (fpx==0)
  //              return iterative_root_base<data__>::no_root_found;

              bool invertible;
              bool modified = false;

                typename iterative_system_root_base<data__, N__, NSOL__>::jacobian_matrix inverse;
                fpx.computeInverseWithCheck(inverse, invertible);

                std::vector<bool> zerodx(N__);

                if (!invertible)
                {
                  for (size_t i=0; i<N__; ++i)
                  {
                    if (std::abs(fpx(i,i)) < std::sqrt(std::numeric_limits<data__>::epsilon()))
                    {
                      zerodx[i] = true;
                      fpx(i,i) = 1.0;
                    }
                    else
                    {
                      zerodx[i] = false;
                    }
                  }
                  modified = true;
                  fpx.computeInverseWithCheck(inverse, invertible);
                  assert(invertible);
                }

                if (invertible)
                {
                  dx = - inverse * eval1;

                  if (modified)
                  {
                    for (size_t i=0; i<N__; ++i)
                    {
                      if (zerodx[i])
                      {
                        dx(i) = 0;
                      }
                    }
                  }
                }
                else
                {
                  dx.setZero();
                }

              dx=this->calculate_delta_factor(x, dx);
              x+=dx;
              fx=fun(x);
              fpx=fprime(x);
              eval1=fx-f0;
              abs_tol_norm=this->calculate_norm(eval1);
              abs_x_norm=this->calculate_norm(dx);
              bool nonzero(false);
              all_zero=true;
              for (size_t i=0; i<N__; ++i)
              {
                // check if stuck and cannot move x anymore
                if (std::abs(dx(i))<=std::numeric_limits<data__>::epsilon())
                {
                  eval3(i)=std::numeric_limits<data__>::epsilon();
                }
                else
                {
                  all_zero=false;
                  eval3(i)=dx(i)/x0(i);
                }

                if (std::abs(f0(i))<=std::numeric_limits<data__>::epsilon())
                  eval2(i)=std::numeric_limits<data__>::epsilon();
                else
                {
                  nonzero=true;
                  eval2(i)=eval1(i)/f0(i);
                }
              }
              if (nonzero)
                rel_tol_norm=this->calculate_norm(eval2);
              else
                rel_tol_norm=static_cast<data__>(0);

              if (all_zero)
                rel_x_norm=static_cast<data__>(0);
              else
                rel_x_norm=this->calculate_norm(eval3);

              ++count;
            }

            root=x;
            if (this->max_iteration_reached(count))
              return this->max_iteration; // could not converge
            if (all_zero)
              return this->hit_constraint; // constraints limited convergence

            return this->converged;
          }

        private:
          typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix x0;
      };

      // Large systems where N__>4
      template<typename data__, size_t N__, size_t NSOL__ = 1>
      class newton_raphson_large_system_method : public iterative_system_root_base_constrained<data__, N__, NSOL__>
      {
      public:
          static const int hit_constraint = 101;

      public:
          newton_raphson_large_system_method()
              : iterative_system_root_base_constrained<data__, N__, NSOL__>()
          {
              x0.setConstant( static_cast<data__>(0) );
          }

          newton_raphson_large_system_method( const newton_raphson_large_system_method<data__, N__, NSOL__> &nrm )
              : iterative_system_root_base_constrained<data__, N__, NSOL__>( nrm ), x0( nrm.x0 )
          {
          }

          ~newton_raphson_large_system_method()
          {
          }

          void set_initial_guess( const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &xg )
          {
              x0 = xg;
          }

          const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix & get_initial_guess() const
          {
              return x0;
          }

          template<typename f__, typename g__>
          int find_root( typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &root, const f__ &fun, const g__ &fprime, const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &f0 ) const
          {
              typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix dx, x( x0 ), fx( fun( x0 ) ), eval1, eval2, eval3;
              typename iterative_system_root_base<data__, N__, NSOL__>::jacobian_matrix fpx( fprime( x0 ) );
              data__ abs_tol_norm, rel_tol_norm, abs_x_norm, rel_x_norm;
              typename iterative_root_base<data__>::iteration_type count;

              // calculate the function evaluated at the initial location
              eval1 = fx - f0;
              abs_tol_norm = this->calculate_norm( eval1 );
              eval2 = (fx - f0).array() / f0.array();
              eval2.setConstant( 1 );
              rel_tol_norm = this->calculate_norm( eval2 );
              if ( this->test_converged( 0, rel_tol_norm, abs_tol_norm, 0, 0 ) )
              {
                  root = x;
                  return this->converged;
              }

              bool all_zero( false );
              abs_x_norm = 0;
              rel_x_norm = 0;
              count = 0;
              while ( !this->test_converged( count, rel_tol_norm, abs_tol_norm, rel_x_norm, abs_x_norm ) && !all_zero )
              {
                  // FIX: Don't have any easy (efficient) way of determining if matrix in invertible
                  //            if (fpx==0)
                  //              return iterative_root_base<data__>::no_root_found;

                  dx = -fpx.lu().solve( eval1 );

                  dx = this->calculate_delta_factor( x, dx );
                  x += dx;
                  fx = fun( x );
                  fpx = fprime( x );
                  eval1 = fx - f0;
                  abs_tol_norm = this->calculate_norm( eval1 );
                  abs_x_norm = this->calculate_norm( dx );
                  bool nonzero( false );
                  all_zero = true;
                  for ( size_t i = 0; i<N__; ++i )
                  {
                      // check if stuck and cannot move x anymore
                      if ( std::abs( dx( i ) ) <= std::numeric_limits<data__>::epsilon() )
                      {
                          eval3( i ) = std::numeric_limits<data__>::epsilon();
                      }
                      else
                      {
                          all_zero = false;
                          eval3( i ) = dx( i ) / x0( i );
                      }

                      if ( std::abs( f0( i ) ) <= std::numeric_limits<data__>::epsilon() )
                          eval2( i ) = std::numeric_limits<data__>::epsilon();
                      else
                      {
                          nonzero = true;
                          eval2( i ) = eval1( i ) / f0( i );
                      }
                  }
                  if ( nonzero )
                      rel_tol_norm = this->calculate_norm( eval2 );
                  else
                      rel_tol_norm = static_cast<data__>(0);

                  if ( all_zero )
                      rel_x_norm = static_cast<data__>(0);
                  else
                      rel_x_norm = this->calculate_norm( eval3 );

                  ++count;
              }

              root = x;
              if ( this->max_iteration_reached( count ) )
                  return this->max_iteration; // could not converge
              if ( all_zero )
                  return this->hit_constraint; // constraints limited convergence

              return this->converged;
          }

      private:
          typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix x0;
      };
    }
  }
}
#endif
<commit_msg>Modify Newton system solver to improve singular matrix workaround.<commit_after>/*********************************************************************************
* Copyright (c) 2013 David D. Marshall <ddmarsha@calpoly.edu>
*
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
*    David D. Marshall - initial code and implementation
********************************************************************************/

#ifndef eli_mutil_nls_newton_raphson_system_method_hpp
#define eli_mutil_nls_newton_raphson_system_method_hpp

#include "eli/code_eli.hpp"

#include "eli/mutil/nls/iterative_system_root_base_constrained.hpp"

namespace eli
{
  namespace mutil
  {
    namespace nls
    {
      // Small systems where N__<=4
      template<typename data__, size_t N__, size_t NSOL__=1>
      class newton_raphson_system_method : public iterative_system_root_base_constrained<data__, N__, NSOL__>
      {
        public:
          static const int hit_constraint = 101;

        public:
          newton_raphson_system_method()
          : iterative_system_root_base_constrained<data__, N__, NSOL__>()
          {
            x0.setConstant(static_cast<data__>(0));
          }

          newton_raphson_system_method(const newton_raphson_system_method<data__, N__, NSOL__> &nrm)
          : iterative_system_root_base_constrained<data__, N__, NSOL__>(nrm), x0(nrm.x0)
          {
          }

          ~newton_raphson_system_method()
          {
          }

          void set_initial_guess(const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &xg)
          {
            x0=xg;
          }

          const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix & get_initial_guess() const
          {
            return x0;
          }

          template<typename f__, typename g__>
          int find_root(typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &root, const f__ &fun, const g__ &fprime, const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &f0) const
          {
            typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix dx, x(x0), fx(fun(x0)), eval1, eval2, eval3;
            typename iterative_system_root_base<data__, N__, NSOL__>::jacobian_matrix fpx(fprime(x0));
            data__ abs_tol_norm, rel_tol_norm, abs_x_norm, rel_x_norm;
            typename iterative_root_base<data__>::iteration_type count;

            // calculate the function evaluated at the initial location
            eval1=fx-f0;
            abs_tol_norm=this->calculate_norm(eval1);
            eval2=(fx-f0).array()/f0.array();
            eval2.setConstant(1);
            rel_tol_norm=this->calculate_norm(eval2);
            if (this->test_converged(0, rel_tol_norm, abs_tol_norm, 0, 0))
            {
              root=x;
              return this->converged;
            }

            bool all_zero(false);
            abs_x_norm=0;
            rel_x_norm=0;
            count=0;
            while (!this->test_converged(count, rel_tol_norm, abs_tol_norm, rel_x_norm, abs_x_norm) && !all_zero)
            {
  // FIX: Don't have any easy (efficient) way of determining if matrix in invertible
  //            if (fpx==0)
  //              return iterative_root_base<data__>::no_root_found;

              bool invertible;
              bool modified = false;

                typename iterative_system_root_base<data__, N__, NSOL__>::jacobian_matrix inverse;
                fpx.computeInverseWithCheck(inverse, invertible);

                std::vector<bool> zerodx(N__);

                if (!invertible)
                {
                  size_t itries = 0;
                  while ( itries < N__ && !invertible )
                  {
                    size_t ismall = -1;
                    data__ fsmall = 1;

                    for (size_t i=0; i<N__; ++i)
                    {
                      if ( std::abs( fpx( i, i ) < fsmall ) )
                      {
                        fsmall = std::abs( fpx ( i, i ) );
                        ismall = i;
                      }
                    }
                    zerodx[ ismall ] = true;
                    fpx( ismall, ismall ) = 1.0;
                    itries++;
                    modified = true;
                    fpx.computeInverseWithCheck(inverse, invertible);
                  }
                  assert(invertible);
                }

                if (invertible)
                {
                  dx = - inverse * eval1;

                  if (modified)
                  {
                    for (size_t i=0; i<N__; ++i)
                    {
                      if (zerodx[i])
                      {
                        dx(i) = 0;
                      }
                    }
                  }
                }
                else
                {
                  dx.setZero();
                }

              dx=this->calculate_delta_factor(x, dx);
              x+=dx;
              fx=fun(x);
              fpx=fprime(x);
              eval1=fx-f0;
              abs_tol_norm=this->calculate_norm(eval1);
              abs_x_norm=this->calculate_norm(dx);
              bool nonzero(false);
              all_zero=true;
              for (size_t i=0; i<N__; ++i)
              {
                // check if stuck and cannot move x anymore
                if (std::abs(dx(i))<=std::numeric_limits<data__>::epsilon())
                {
                  eval3(i)=std::numeric_limits<data__>::epsilon();
                }
                else
                {
                  all_zero=false;
                  eval3(i)=dx(i)/x0(i);
                }

                if (std::abs(f0(i))<=std::numeric_limits<data__>::epsilon())
                  eval2(i)=std::numeric_limits<data__>::epsilon();
                else
                {
                  nonzero=true;
                  eval2(i)=eval1(i)/f0(i);
                }
              }
              if (nonzero)
                rel_tol_norm=this->calculate_norm(eval2);
              else
                rel_tol_norm=static_cast<data__>(0);

              if (all_zero)
                rel_x_norm=static_cast<data__>(0);
              else
                rel_x_norm=this->calculate_norm(eval3);

              ++count;
            }

            root=x;
            if (this->max_iteration_reached(count))
              return this->max_iteration; // could not converge
            if (all_zero)
              return this->hit_constraint; // constraints limited convergence

            return this->converged;
          }

        private:
          typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix x0;
      };

      // Large systems where N__>4
      template<typename data__, size_t N__, size_t NSOL__ = 1>
      class newton_raphson_large_system_method : public iterative_system_root_base_constrained<data__, N__, NSOL__>
      {
      public:
          static const int hit_constraint = 101;

      public:
          newton_raphson_large_system_method()
              : iterative_system_root_base_constrained<data__, N__, NSOL__>()
          {
              x0.setConstant( static_cast<data__>(0) );
          }

          newton_raphson_large_system_method( const newton_raphson_large_system_method<data__, N__, NSOL__> &nrm )
              : iterative_system_root_base_constrained<data__, N__, NSOL__>( nrm ), x0( nrm.x0 )
          {
          }

          ~newton_raphson_large_system_method()
          {
          }

          void set_initial_guess( const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &xg )
          {
              x0 = xg;
          }

          const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix & get_initial_guess() const
          {
              return x0;
          }

          template<typename f__, typename g__>
          int find_root( typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &root, const f__ &fun, const g__ &fprime, const typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix &f0 ) const
          {
              typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix dx, x( x0 ), fx( fun( x0 ) ), eval1, eval2, eval3;
              typename iterative_system_root_base<data__, N__, NSOL__>::jacobian_matrix fpx( fprime( x0 ) );
              data__ abs_tol_norm, rel_tol_norm, abs_x_norm, rel_x_norm;
              typename iterative_root_base<data__>::iteration_type count;

              // calculate the function evaluated at the initial location
              eval1 = fx - f0;
              abs_tol_norm = this->calculate_norm( eval1 );
              eval2 = (fx - f0).array() / f0.array();
              eval2.setConstant( 1 );
              rel_tol_norm = this->calculate_norm( eval2 );
              if ( this->test_converged( 0, rel_tol_norm, abs_tol_norm, 0, 0 ) )
              {
                  root = x;
                  return this->converged;
              }

              bool all_zero( false );
              abs_x_norm = 0;
              rel_x_norm = 0;
              count = 0;
              while ( !this->test_converged( count, rel_tol_norm, abs_tol_norm, rel_x_norm, abs_x_norm ) && !all_zero )
              {
                  // FIX: Don't have any easy (efficient) way of determining if matrix in invertible
                  //            if (fpx==0)
                  //              return iterative_root_base<data__>::no_root_found;

                  dx = -fpx.lu().solve( eval1 );

                  dx = this->calculate_delta_factor( x, dx );
                  x += dx;
                  fx = fun( x );
                  fpx = fprime( x );
                  eval1 = fx - f0;
                  abs_tol_norm = this->calculate_norm( eval1 );
                  abs_x_norm = this->calculate_norm( dx );
                  bool nonzero( false );
                  all_zero = true;
                  for ( size_t i = 0; i<N__; ++i )
                  {
                      // check if stuck and cannot move x anymore
                      if ( std::abs( dx( i ) ) <= std::numeric_limits<data__>::epsilon() )
                      {
                          eval3( i ) = std::numeric_limits<data__>::epsilon();
                      }
                      else
                      {
                          all_zero = false;
                          eval3( i ) = dx( i ) / x0( i );
                      }

                      if ( std::abs( f0( i ) ) <= std::numeric_limits<data__>::epsilon() )
                          eval2( i ) = std::numeric_limits<data__>::epsilon();
                      else
                      {
                          nonzero = true;
                          eval2( i ) = eval1( i ) / f0( i );
                      }
                  }
                  if ( nonzero )
                      rel_tol_norm = this->calculate_norm( eval2 );
                  else
                      rel_tol_norm = static_cast<data__>(0);

                  if ( all_zero )
                      rel_x_norm = static_cast<data__>(0);
                  else
                      rel_x_norm = this->calculate_norm( eval3 );

                  ++count;
              }

              root = x;
              if ( this->max_iteration_reached( count ) )
                  return this->max_iteration; // could not converge
              if ( all_zero )
                  return this->hit_constraint; // constraints limited convergence

              return this->converged;
          }

      private:
          typename iterative_system_root_base<data__, N__, NSOL__>::solution_matrix x0;
      };
    }
  }
}
#endif
<|endoftext|>


<commit_before>#ifndef SHARED_MEMORY_DATAFACADE_HPP
#define SHARED_MEMORY_DATAFACADE_HPP

// implements all data storage when shared memory _IS_ used

#include "storage/shared_barriers.hpp"
#include "storage/shared_datatype.hpp"
#include "storage/shared_memory.hpp"
#include "engine/datafacade/contiguous_internalmem_datafacade_base.hpp"

namespace osrm
{
namespace engine
{
namespace datafacade
{

/**
 * This datafacade uses an IPC shared memory block as the data location.
 * Many SharedMemoryDataFacade objects can be created that point to the same shared
 * memory block.
 */
class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
{

  protected:
    std::unique_ptr<storage::SharedMemory> m_layout_memory;
    std::unique_ptr<storage::SharedMemory> m_large_memory;
    std::shared_ptr<storage::SharedBarriers> shared_barriers;
    storage::SharedDataType layout_region;
    storage::SharedDataType data_region;
    unsigned shared_timestamp;

    SharedMemoryDataFacade() {}

  public:
    // this function handle the deallocation of the shared memory it we can prove it will not be
    // used anymore.  We crash hard here if something goes wrong (noexcept).
    virtual ~SharedMemoryDataFacade() noexcept
    {
        boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock(
            data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
                                           : shared_barriers->regions_2_mutex,
            boost::interprocess::defer_lock);

        // if this returns false this is still in use
        if (exclusive_lock.try_lock())
        {
            // Now check if this is still the newest dataset
            const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
                lock(shared_barriers->current_regions_mutex);

            auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
            const auto current_timestamp =
                static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());

            if (current_timestamp->timestamp == shared_timestamp)
            {
                util::Log(logDEBUG) << "Retaining data with shared timestamp " << shared_timestamp;
            }
            else
            {
                storage::SharedMemory::Remove(data_region);
                storage::SharedMemory::Remove(layout_region);
            }
        }
    }

    SharedMemoryDataFacade(const std::shared_ptr<storage::SharedBarriers> &shared_barriers_,
                           storage::SharedDataType layout_region_,
                           storage::SharedDataType data_region_,
                           unsigned shared_timestamp_)
        : shared_barriers(shared_barriers_), layout_region(layout_region_),
          data_region(data_region_), shared_timestamp(shared_timestamp_)
    {
        util::Log(logDEBUG) << "Loading new data with shared timestamp " << shared_timestamp;

        BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
        m_layout_memory = storage::makeSharedMemory(layout_region);

        BOOST_ASSERT(storage::SharedMemory::RegionExists(data_region));
        m_large_memory = storage::makeSharedMemory(data_region);

        InitializeInternalPointers(*reinterpret_cast<storage::DataLayout *>(m_layout_memory->Ptr()),
                                   reinterpret_cast<char *>(m_large_memory->Ptr()));
    }
};
}
}
}

#endif // SHARED_MEMORY_DATAFACADE_HPP
<commit_msg>Fix removing shared memory segments in a multi-process setup<commit_after>#ifndef SHARED_MEMORY_DATAFACADE_HPP
#define SHARED_MEMORY_DATAFACADE_HPP

// implements all data storage when shared memory _IS_ used

#include "storage/shared_barriers.hpp"
#include "storage/shared_datatype.hpp"
#include "storage/shared_memory.hpp"
#include "engine/datafacade/contiguous_internalmem_datafacade_base.hpp"

namespace osrm
{
namespace engine
{
namespace datafacade
{

/**
 * This datafacade uses an IPC shared memory block as the data location.
 * Many SharedMemoryDataFacade objects can be created that point to the same shared
 * memory block.
 */
class SharedMemoryDataFacade : public ContiguousInternalMemoryDataFacadeBase
{

  protected:
    std::unique_ptr<storage::SharedMemory> m_layout_memory;
    std::unique_ptr<storage::SharedMemory> m_large_memory;
    std::shared_ptr<storage::SharedBarriers> shared_barriers;
    storage::SharedDataType layout_region;
    storage::SharedDataType data_region;
    unsigned shared_timestamp;

    SharedMemoryDataFacade() {}

  public:
    // this function handle the deallocation of the shared memory it we can prove it will not be
    // used anymore.  We crash hard here if something goes wrong (noexcept).
    virtual ~SharedMemoryDataFacade() noexcept
    {
        boost::interprocess::scoped_lock<boost::interprocess::named_sharable_mutex> exclusive_lock(
            data_region == storage::DATA_1 ? shared_barriers->regions_1_mutex
                                           : shared_barriers->regions_2_mutex,
            boost::interprocess::defer_lock);

        // if this returns false this is still in use
        if (exclusive_lock.try_lock())
        {
            if (storage::SharedMemory::RegionExists(data_region))
            {
                BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));

                // Now check if this is still the newest dataset
                const boost::interprocess::sharable_lock<boost::interprocess::named_upgradable_mutex>
                    lock(shared_barriers->current_regions_mutex);

                auto shared_regions = storage::makeSharedMemory(storage::CURRENT_REGIONS);
                const auto current_timestamp =
                    static_cast<const storage::SharedDataTimestamp *>(shared_regions->Ptr());

                if (current_timestamp->timestamp == shared_timestamp)
                {
                    util::Log(logDEBUG) << "Retaining data with shared timestamp " << shared_timestamp;
                }
                else
                {
                    storage::SharedMemory::Remove(data_region);
                    storage::SharedMemory::Remove(layout_region);
                }
            }
        }
    }

    SharedMemoryDataFacade(const std::shared_ptr<storage::SharedBarriers> &shared_barriers_,
                           storage::SharedDataType layout_region_,
                           storage::SharedDataType data_region_,
                           unsigned shared_timestamp_)
        : shared_barriers(shared_barriers_), layout_region(layout_region_),
          data_region(data_region_), shared_timestamp(shared_timestamp_)
    {
        util::Log(logDEBUG) << "Loading new data with shared timestamp " << shared_timestamp;

        BOOST_ASSERT(storage::SharedMemory::RegionExists(layout_region));
        m_layout_memory = storage::makeSharedMemory(layout_region);

        BOOST_ASSERT(storage::SharedMemory::RegionExists(data_region));
        m_large_memory = storage::makeSharedMemory(data_region);

        InitializeInternalPointers(*reinterpret_cast<storage::DataLayout *>(m_layout_memory->Ptr()),
                                   reinterpret_cast<char *>(m_large_memory->Ptr()));
    }
};
}
}
}

#endif // SHARED_MEMORY_DATAFACADE_HPP
<|endoftext|>


<commit_before>//MIT License
//Copyright 2017 Patrick Laughrea
#include "parser.hpp"

#include "utilsHtml.hpp"
#include "utilsSweepers.hpp"

using namespace ntt;
using namespace std;
using namespace various;

static void splitString(string& left, string& right, string::size_type index, string::size_type length = 1);

Parser::Parser(SmartIterator it) : it(move(it)) {}
Parser::~Parser() {}

static void replaceAll(string& s, const string& from, const string& to)
{
	for (string::size_type i = 0; (i = s.find(from, i)) != string::npos; i += to.length())
		s.replace(i, from.length(), to);
}

static string filterHtml(string&& s)
{
	trimHtmlTags(s);
	vector<string> from = {" ", "<", ">", """, "'"};
	vector<string> to = {" ", "<", ">", "\"", "\'"};
	for (vector<string>::size_type i = 0; i < from.size(); ++i)
		replaceAll(s, from[i], to[i]);
	return s;
}

vector<string> Parser::parse()
{
	vector<string> lines;
	readStart();
	lines.push_back(filterHtml(move(left)));
	while (getLine())
		lines.push_back(filterHtml(move(left)));
	return lines;
}

void Parser::readStart()
{
	//in note file, text immediately follows body, so get it
	//and put text in next tag in leftover for use later
	getToTag(it, HtmlTag::BODY, false);
	readToTag(it, HtmlTag::DIV, false, left);
	readToTag(it, HtmlTag::DIV, true, leftover);
}

bool Parser::getLine()
{
    readNextTag();
    return !left.empty() || it;
}

void Parser::readNextTag()
{
    if (leftover.length() > 0)
    {
        left = move(leftover);
        leftover.clear(); //to be sure it's now empty
    }
    else if (!(readToTag(it, HtmlTag::DIV, false, left) && readToTag(it, HtmlTag::DIV, true, left)))
    {
        //there could still be text after the last tag, before the ending body tag
        string tag = makeTagString<true>(HtmlTag::BODY);
        auto index = left.find(tag);
        if (index != string::npos)
            left.erase(index);
        else
            left.clear();
    }
    else
    {
        string tag = makeTagString<false>(HtmlTag::DIV);
        auto index = left.find(tag);
        if (index != string::npos)
            splitString(left, leftover, index, tag.length());
    }
}

//takes the left string and puts all the part after the index into the right string
//the part in the middle (the index + length) is removed
static void splitString(string& left, string& right, string::size_type index, string::size_type length)
{
    if (index + length < left.length())
        right = left.substr(index + length);
    else
        right.clear();

    if (index < left.length())
        left = left.erase(index);
}<commit_msg>Fix case of two divs in a row<commit_after>//MIT License
//Copyright 2017 Patrick Laughrea
#include "parser.hpp"

#include "utilsHtml.hpp"
#include "utilsSweepers.hpp"

using namespace ntt;
using namespace std;
using namespace various;

static void splitString(string& left, string& right, string::size_type index, string::size_type length = 1);

Parser::Parser(SmartIterator it) : it(move(it)) {}
Parser::~Parser() {}

static void replaceAll(string& s, const string& from, const string& to)
{
	for (string::size_type i = 0; (i = s.find(from, i)) != string::npos; i += to.length())
		s.replace(i, from.length(), to);
}

static string filterHtml(string&& s)
{
	trimHtmlTags(s);
	vector<string> from = {" ", "<", ">", """, "'"};
	vector<string> to = {" ", "<", ">", "\"", "\'"};
	for (vector<string>::size_type i = 0; i < from.size(); ++i)
		replaceAll(s, from[i], to[i]);
	return s;
}

vector<string> Parser::parse()
{
	vector<string> lines;
	readStart();
	lines.push_back(filterHtml(move(left)));
	while (getLine())
		lines.push_back(filterHtml(move(left)));
	return lines;
}

void Parser::readStart()
{
	//in note file, text immediately follows body, so get it
	//and put text in next tag in leftover for use later
	getToTag(it, HtmlTag::BODY, false);
	readToTag(it, HtmlTag::DIV, false, left);
	readToTag(it, HtmlTag::DIV, true, leftover);
}

bool Parser::getLine()
{
    readNextTag();
    return !left.empty() || it;
}

void Parser::readNextTag()
{
    if (leftover.length() > 0)
    {
        left = move(leftover);
        leftover.clear(); //to be sure it's now empty
    }
    else if (!(readToTag(it, HtmlTag::DIV, false, left) && readToTag(it, HtmlTag::DIV, true, left)))
    {
        //there could still be text after the last tag, before the ending body tag
        string tag = makeTagString<true>(HtmlTag::BODY);
        auto index = left.find(tag);
        if (index != string::npos)
            left.erase(index);
        else
            left.clear();
    }
    else
    {
        string tag = makeTagString<false>(HtmlTag::DIV);
        auto index = left.find(tag);
        if (index != string::npos && index != 0)
            splitString(left, leftover, index, tag.length());
    }
}

//takes the left string and puts all the part after the index into the right string
//the part in the middle (the index + length) is removed
static void splitString(string& left, string& right, string::size_type index, string::size_type length)
{
    if (index + length < left.length())
        right = left.substr(index + length);
    else
        right.clear();

    if (index < left.length())
        left = left.erase(index);
}<|endoftext|>


<commit_before>/*************************************************************************
 *
 *  $RCSfile: escherex.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: sj $ $Date: 2000-12-12 17:32:48 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _PptEscherEx_HXX
#include "escherex.hxx"
#endif

// ---------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------

PptEscherEx::PptEscherEx( SvStream& rOutStrm, UINT32 nDrawings ) :
    EscherEx                ( rOutStrm, nDrawings )
{
    mnFIDCLs = nDrawings;
    mnCurrentDg = 0;
    mnCurrentShapeID = 0;
    mnTotalShapesDgg = 0;
    mnCurrentShapeMaximumID = 0;
}

// ---------------------------------------------------------------------------------------------

sal_uInt32 PptEscherEx::DrawingGroupContainerSize()
{
    return ImplDggContainerSize() + 8;
}

void PptEscherEx::WriteDrawingGroupContainer( SvStream& rSt )
{
    UINT32 nSize = DrawingGroupContainerSize();
    rSt << (sal_uInt32)( 0xf | ( 1035 << 16 ) )     // EPP_PPDrawingGroup
        << (sal_uInt32)( nSize - 8 );

    ImplWriteDggContainer( rSt );
}

// ---------------------------------------------------------------------------------------------

sal_uInt32 PptEscherEx::ImplDggContainerSize()
{
    UINT32 nSize;

    nSize  = ImplDggAtomSize();
    nSize += GetBlibStoreContainerSize();
    nSize += ImplOptAtomSize();
    nSize += ImplSplitMenuColorsAtomSize();

    return nSize + 8;
}

void PptEscherEx::ImplWriteDggContainer( SvStream& rSt )
{
    sal_uInt32 nSize = ImplDggContainerSize();
    if ( nSize )
    {
        rSt << (sal_uInt32)( 0xf | ( ESCHER_DggContainer << 16 ) )
            << (sal_uInt32)( nSize - 8 );

        ImplWriteDggAtom( rSt );
        WriteBlibStoreContainer( rSt );
        ImplWriteOptAtom( rSt );
        ImplWriteSplitMenuColorsAtom( rSt );
    }
}

// ---------------------------------------------------------------------------------------------

sal_uInt32 PptEscherEx::ImplDggAtomSize()
{
    return maFIDCLs.Tell() + 24;
}

void PptEscherEx::ImplWriteDggAtom( SvStream& rSt )
{
    sal_uInt32 nSize = ImplDggAtomSize();
    if ( nSize )
    {
        rSt << (sal_uInt32)( ESCHER_Dgg << 16 )
            << (sal_uInt32)( nSize - 8 )
            << mnCurrentShapeID
            << (sal_uInt32)( mnFIDCLs + 1 )
            << mnTotalShapesDgg
            << mnDrawings;

        rSt.Write( maFIDCLs.GetData(), nSize - 24 );
    }
}

// ---------------------------------------------------------------------------------------------

#define ESCHER_OPT_COUNT 6

sal_uInt32 PptEscherEx::ImplOptAtomSize()
{
    sal_uInt32 nSize = 0;
    if ( ESCHER_OPT_COUNT )
        nSize = ( ESCHER_OPT_COUNT * 6 ) + 8;
    return nSize;
}

void PptEscherEx::ImplWriteOptAtom( SvStream& rSt )
{
    sal_uInt32 nSize = ImplOptAtomSize();
    if ( nSize )
    {
        rSt << (sal_uInt32)( ( ESCHER_OPT << 16 ) | ( ESCHER_OPT_COUNT << 4 ) | 0x3 )
            << (sal_uInt32)( nSize - 8 )
            << (sal_uInt16)ESCHER_Prop_fillColor            << (sal_uInt32)0xffb800
            << (sal_uInt16)ESCHER_Prop_fillBackColor        << (sal_uInt32)0
            << (sal_uInt16)ESCHER_Prop_fNoFillHitTest       << (sal_uInt32)0x00100010
            << (sal_uInt16)ESCHER_Prop_lineColor            << (sal_uInt32)0x8000001
            << (sal_uInt16)ESCHER_Prop_fNoLineDrawDash      << (sal_uInt32)0x00080008
            << (sal_uInt16)ESCHER_Prop_shadowColor          << (sal_uInt32)0x8000002;
    }
}

// ---------------------------------------------------------------------------------------------

#define ESCHER_SPLIT_MENU_COLORS_COUNT  4

sal_uInt32 PptEscherEx::ImplSplitMenuColorsAtomSize()
{
    sal_uInt32 nSize = 0;
    if ( ESCHER_SPLIT_MENU_COLORS_COUNT )
        nSize = ( ESCHER_SPLIT_MENU_COLORS_COUNT << 2 ) + 8;
    return nSize;
}

void PptEscherEx::ImplWriteSplitMenuColorsAtom( SvStream& rSt )
{
    UINT32 nSize = ImplSplitMenuColorsAtomSize();
    if ( nSize )
    {
        rSt << (sal_uInt32)( ( ESCHER_SplitMenuColors << 16 ) | ( ESCHER_SPLIT_MENU_COLORS_COUNT << 4 ) )
            << (sal_uInt32)( nSize - 8 )
            << (sal_uInt32)0x08000004
            << (sal_uInt32)0x08000001
            << (sal_uInt32)0x08000002
            << (sal_uInt32)0x100000f7;
    }

}

// ---------------------------------------------------------------------------------------------

PptEscherEx::~PptEscherEx()
{
}

// ---------------------------------------------------------------------------------------------

void PptEscherEx::OpenContainer( UINT16 n_EscherContainer, int nRecInstance )
{
    *mpOutStrm << (UINT16)( ( nRecInstance << 4 ) | 0xf  ) << n_EscherContainer << (UINT32)0;
    mpOffsets[ ++mnLevel ] = mpOutStrm->Tell() - 4;
    mpRecTypes[ mnLevel ] = n_EscherContainer;

    switch( n_EscherContainer )
    {
        case ESCHER_DgContainer :
        {
            if ( !mbEscherDg )
            {
                mbEscherDg = TRUE;
                mnCurrentDg++;
                mnTotalShapesDg = 0;
                mnTotalShapeIdUsedDg = 0;
                mnCurrentShapeID = ( mnCurrentShapeMaximumID &~0x3ff ) + 0x400; // eine neue Seite bekommt immer eine neue ShapeId die ein vielfaches von 1024 ist,
                                                                                // damit ist erste aktuelle Shape ID 0x400
                AddAtom( 8, ESCHER_Dg, 0, mnCurrentDg );
                PtReplaceOrInsert( ESCHER_Persist_Dg | mnCurrentDg, mpOutStrm->Tell() );
                *mpOutStrm << (UINT32)0     // The number of shapes in this drawing
                           << (UINT32)0;    // The last MSOSPID given to an SP in this DG
            }
        }
        break;

        case ESCHER_SpgrContainer :
        {
            if ( mbEscherDg )
            {
                mbEscherSpgr = TRUE;
            }
        }
        break;

        case ESCHER_SpContainer :
        {
        }
        break;

        default:
        break;
    }
}

// ---------------------------------------------------------------------------------------------

void PptEscherEx::CloseContainer()
{
    UINT32 nSize, nPos = mpOutStrm->Tell();
    nSize = ( nPos - mpOffsets[ mnLevel ] ) - 4;
    mpOutStrm->Seek( mpOffsets[ mnLevel ] );
    *mpOutStrm << nSize;

    switch( mpRecTypes[ mnLevel ] )
    {
        case ESCHER_DgContainer :
        {
            if ( mbEscherDg )
            {
                mbEscherDg = FALSE;
                if ( DoSeek( ESCHER_Persist_Dg | mnCurrentDg ) )
                {
                    // shapeanzahl des drawings setzen
                    mnTotalShapesDgg += mnTotalShapesDg;
                    *mpOutStrm << mnTotalShapesDg << mnCurrentShapeMaximumID;

                    if ( !mnTotalShapesDg )
                    {
                        maFIDCLs << (UINT32)0
                                 << (UINT32)0;
                    }
                    else
                    {
                        if ( mnTotalShapeIdUsedDg )
                        {
                            UINT32 i, nFIDCL = ( ( mnTotalShapeIdUsedDg - 1 ) / 0x400 );
                            if ( nFIDCL )
                                mnFIDCLs += nFIDCL;
                            for ( i = 0; i <= nFIDCL; i++ )
                            {
                                maFIDCLs << mnCurrentDg;            // drawing number
                                if ( i < nFIDCL )
                                    maFIDCLs << 0x400;
                                else
                                {
                                    UINT32 nShapesLeft = mnTotalShapeIdUsedDg % 0x400;
                                    if ( !nShapesLeft )
                                        nShapesLeft = 0x400;        // shape count in this IDCL
                                    maFIDCLs << (UINT32)nShapesLeft;
                                }
                            }
                        }
                    }
                }
            }
        }
        break;

        case ESCHER_SpgrContainer :
        {
            if ( mbEscherSpgr )
            {
                mbEscherSpgr = FALSE;

            }
        }
        break;

        default:
        break;
    }
    --mnLevel;
    mpOutStrm->Seek( nPos );
}

// ---------------------------------------------------------------------------------------------

void PptEscherEx::EnterGroup( Rectangle* pBoundRect, SvMemoryStream* pClientData )
{
    Rectangle aRect;
    if ( pBoundRect )
        aRect = *pBoundRect;

    OpenContainer( ESCHER_SpgrContainer );
    OpenContainer( ESCHER_SpContainer );
    AddAtom( 16, ESCHER_Spgr, 1 );
    PtReplaceOrInsert( ESCHER_Persist_Grouping_Snap | mnGroupLevel, mpOutStrm->Tell() );
    *mpOutStrm  << (INT32)aRect.Left()  // Bounding box fuer die Gruppierten shapes an die sie attached werden
                << (INT32)aRect.Top()
                << (INT32)aRect.Right()
                << (INT32)aRect.Bottom();

    if ( !mnGroupLevel )
        AddShape( ESCHER_ShpInst_Min, 5 );                              // Flags: Group | Patriarch
    else
    {
        AddShape( ESCHER_ShpInst_Min, 0x201 );                          // Flags: Group | HaveAnchor
        AddAtom( 8, ESCHER_ClientAnchor );
        PtReplaceOrInsert( ESCHER_Persist_Grouping_Logic | mnGroupLevel, mpOutStrm->Tell() );
        *mpOutStrm << (INT16)aRect.Top() << (INT16)aRect.Left() << (INT16)aRect.Right() << (INT16)aRect.Bottom();
    }
    if ( pClientData )
    {
        pClientData->Seek( STREAM_SEEK_TO_END );
        sal_uInt32 nSize = pClientData->Tell();
        if ( nSize )
        {
            *mpOutStrm << (sal_uInt32)( ( ESCHER_ClientData << 16 ) | 0xf )
                       << nSize;
            mpOutStrm->Write( pClientData->GetData(), nSize );
        }
    }
    CloseContainer();                                               // ESCHER_SpContainer
    mnGroupLevel++;
}

// ---------------------------------------------------------------------------------------------
<commit_msg>INTEGRATION: CWS impress6ea1 (1.8.402); FILE MERGED 2004/03/30 16:05:26 sj 1.8.402.2: #i26747# added grouping depth limit 2004/03/29 15:41:10 sj 1.8.402.1: #i26747# fixed crash if exporting group objects with a depth higher than 32<commit_after>/*************************************************************************
 *
 *  $RCSfile: escherex.cxx,v $
 *
 *  $Revision: 1.9 $
 *
 *  last change: $Author: hr $ $Date: 2004-04-07 11:10:24 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (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.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#ifndef _PptEscherEx_HXX
#include "escherex.hxx"
#endif

// ---------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------
// ---------------------------------------------------------------------------------------------

PptEscherEx::PptEscherEx( SvStream& rOutStrm, UINT32 nDrawings ) :
    EscherEx                ( rOutStrm, nDrawings )
{
    mnFIDCLs = nDrawings;
    mnCurrentDg = 0;
    mnCurrentShapeID = 0;
    mnTotalShapesDgg = 0;
    mnCurrentShapeMaximumID = 0;
}

// ---------------------------------------------------------------------------------------------

sal_uInt32 PptEscherEx::DrawingGroupContainerSize()
{
    return ImplDggContainerSize() + 8;
}

void PptEscherEx::WriteDrawingGroupContainer( SvStream& rSt )
{
    UINT32 nSize = DrawingGroupContainerSize();
    rSt << (sal_uInt32)( 0xf | ( 1035 << 16 ) )     // EPP_PPDrawingGroup
        << (sal_uInt32)( nSize - 8 );

    ImplWriteDggContainer( rSt );
}

// ---------------------------------------------------------------------------------------------

sal_uInt32 PptEscherEx::ImplDggContainerSize()
{
    UINT32 nSize;

    nSize  = ImplDggAtomSize();
    nSize += GetBlibStoreContainerSize();
    nSize += ImplOptAtomSize();
    nSize += ImplSplitMenuColorsAtomSize();

    return nSize + 8;
}

void PptEscherEx::ImplWriteDggContainer( SvStream& rSt )
{
    sal_uInt32 nSize = ImplDggContainerSize();
    if ( nSize )
    {
        rSt << (sal_uInt32)( 0xf | ( ESCHER_DggContainer << 16 ) )
            << (sal_uInt32)( nSize - 8 );

        ImplWriteDggAtom( rSt );
        WriteBlibStoreContainer( rSt );
        ImplWriteOptAtom( rSt );
        ImplWriteSplitMenuColorsAtom( rSt );
    }
}

// ---------------------------------------------------------------------------------------------

sal_uInt32 PptEscherEx::ImplDggAtomSize()
{
    return maFIDCLs.Tell() + 24;
}

void PptEscherEx::ImplWriteDggAtom( SvStream& rSt )
{
    sal_uInt32 nSize = ImplDggAtomSize();
    if ( nSize )
    {
        rSt << (sal_uInt32)( ESCHER_Dgg << 16 )
            << (sal_uInt32)( nSize - 8 )
            << mnCurrentShapeID
            << (sal_uInt32)( mnFIDCLs + 1 )
            << mnTotalShapesDgg
            << mnDrawings;

        rSt.Write( maFIDCLs.GetData(), nSize - 24 );
    }
}

// ---------------------------------------------------------------------------------------------

#define ESCHER_OPT_COUNT 6

sal_uInt32 PptEscherEx::ImplOptAtomSize()
{
    sal_uInt32 nSize = 0;
    if ( ESCHER_OPT_COUNT )
        nSize = ( ESCHER_OPT_COUNT * 6 ) + 8;
    return nSize;
}

void PptEscherEx::ImplWriteOptAtom( SvStream& rSt )
{
    sal_uInt32 nSize = ImplOptAtomSize();
    if ( nSize )
    {
        rSt << (sal_uInt32)( ( ESCHER_OPT << 16 ) | ( ESCHER_OPT_COUNT << 4 ) | 0x3 )
            << (sal_uInt32)( nSize - 8 )
            << (sal_uInt16)ESCHER_Prop_fillColor            << (sal_uInt32)0xffb800
            << (sal_uInt16)ESCHER_Prop_fillBackColor        << (sal_uInt32)0
            << (sal_uInt16)ESCHER_Prop_fNoFillHitTest       << (sal_uInt32)0x00100010
            << (sal_uInt16)ESCHER_Prop_lineColor            << (sal_uInt32)0x8000001
            << (sal_uInt16)ESCHER_Prop_fNoLineDrawDash      << (sal_uInt32)0x00080008
            << (sal_uInt16)ESCHER_Prop_shadowColor          << (sal_uInt32)0x8000002;
    }
}

// ---------------------------------------------------------------------------------------------

#define ESCHER_SPLIT_MENU_COLORS_COUNT  4

sal_uInt32 PptEscherEx::ImplSplitMenuColorsAtomSize()
{
    sal_uInt32 nSize = 0;
    if ( ESCHER_SPLIT_MENU_COLORS_COUNT )
        nSize = ( ESCHER_SPLIT_MENU_COLORS_COUNT << 2 ) + 8;
    return nSize;
}

void PptEscherEx::ImplWriteSplitMenuColorsAtom( SvStream& rSt )
{
    UINT32 nSize = ImplSplitMenuColorsAtomSize();
    if ( nSize )
    {
        rSt << (sal_uInt32)( ( ESCHER_SplitMenuColors << 16 ) | ( ESCHER_SPLIT_MENU_COLORS_COUNT << 4 ) )
            << (sal_uInt32)( nSize - 8 )
            << (sal_uInt32)0x08000004
            << (sal_uInt32)0x08000001
            << (sal_uInt32)0x08000002
            << (sal_uInt32)0x100000f7;
    }

}

// ---------------------------------------------------------------------------------------------

PptEscherEx::~PptEscherEx()
{
}

// ---------------------------------------------------------------------------------------------

void PptEscherEx::OpenContainer( UINT16 n_EscherContainer, int nRecInstance )
{
    *mpOutStrm << (UINT16)( ( nRecInstance << 4 ) | 0xf  ) << n_EscherContainer << (UINT32)0;
    mOffsets.push_back( mpOutStrm->Tell() - 4 );
    mRecTypes.push_back( n_EscherContainer );

    switch( n_EscherContainer )
    {
        case ESCHER_DgContainer :
        {
            if ( !mbEscherDg )
            {
                mbEscherDg = TRUE;
                mnCurrentDg++;
                mnTotalShapesDg = 0;
                mnTotalShapeIdUsedDg = 0;
                mnCurrentShapeID = ( mnCurrentShapeMaximumID &~0x3ff ) + 0x400; // eine neue Seite bekommt immer eine neue ShapeId die ein vielfaches von 1024 ist,
                                                                                // damit ist erste aktuelle Shape ID 0x400
                AddAtom( 8, ESCHER_Dg, 0, mnCurrentDg );
                PtReplaceOrInsert( ESCHER_Persist_Dg | mnCurrentDg, mpOutStrm->Tell() );
                *mpOutStrm << (UINT32)0     // The number of shapes in this drawing
                           << (UINT32)0;    // The last MSOSPID given to an SP in this DG
            }
        }
        break;

        case ESCHER_SpgrContainer :
        {
            if ( mbEscherDg )
            {
                mbEscherSpgr = TRUE;
            }
        }
        break;

        case ESCHER_SpContainer :
        {
        }
        break;

        default:
        break;
    }
}

// ---------------------------------------------------------------------------------------------

void PptEscherEx::CloseContainer()
{
    /* SJ: #Issue 26747#
       not creating group objects with a depth higher than 16, because then
       PPT is having a big performance problem when starting a slide show
    */
    if ( ( mRecTypes.back() != ESCHER_SpgrContainer ) || ( mnGroupLevel < 12 ) )
    {
        UINT32 nSize, nPos = mpOutStrm->Tell();
        nSize = ( nPos - mOffsets.back() ) - 4;
        mpOutStrm->Seek( mOffsets.back() );
        *mpOutStrm << nSize;

        switch( mRecTypes.back() )
        {
            case ESCHER_DgContainer :
            {
                if ( mbEscherDg )
                {
                    mbEscherDg = FALSE;
                    if ( DoSeek( ESCHER_Persist_Dg | mnCurrentDg ) )
                    {
                        // shapeanzahl des drawings setzen
                        mnTotalShapesDgg += mnTotalShapesDg;
                        *mpOutStrm << mnTotalShapesDg << mnCurrentShapeMaximumID;

                        if ( !mnTotalShapesDg )
                        {
                            maFIDCLs << (UINT32)0
                                    << (UINT32)0;
                        }
                        else
                        {
                            if ( mnTotalShapeIdUsedDg )
                            {
                                UINT32 i, nFIDCL = ( ( mnTotalShapeIdUsedDg - 1 ) / 0x400 );
                                if ( nFIDCL )
                                    mnFIDCLs += nFIDCL;
                                for ( i = 0; i <= nFIDCL; i++ )
                                {
                                    maFIDCLs << mnCurrentDg;            // drawing number
                                    if ( i < nFIDCL )
                                        maFIDCLs << 0x400;
                                    else
                                    {
                                        UINT32 nShapesLeft = mnTotalShapeIdUsedDg % 0x400;
                                        if ( !nShapesLeft )
                                            nShapesLeft = 0x400;        // shape count in this IDCL
                                        maFIDCLs << (UINT32)nShapesLeft;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            break;

            case ESCHER_SpgrContainer :
            {
                if ( mbEscherSpgr )
                {
                    mbEscherSpgr = FALSE;

                }
            }
            break;

            default:
            break;
        }
        mOffsets.pop_back();
        mRecTypes.pop_back();
        mpOutStrm->Seek( nPos );
    }
}

// ---------------------------------------------------------------------------------------------

void PptEscherEx::EnterGroup( Rectangle* pBoundRect, SvMemoryStream* pClientData )
{
    /* SJ: #Issue 26747#
       not creating group objects with a depth higher than 16, because then
       PPT is having a big performance problem when starting a slide show
    */
    if ( mnGroupLevel < 12 )
    {
        Rectangle aRect;
        if ( pBoundRect )
            aRect = *pBoundRect;

        OpenContainer( ESCHER_SpgrContainer );
        OpenContainer( ESCHER_SpContainer );
        AddAtom( 16, ESCHER_Spgr, 1 );
        PtReplaceOrInsert( ESCHER_Persist_Grouping_Snap | mnGroupLevel, mpOutStrm->Tell() );
        *mpOutStrm  << (INT32)aRect.Left()  // Bounding box fuer die Gruppierten shapes an die sie attached werden
                    << (INT32)aRect.Top()
                    << (INT32)aRect.Right()
                    << (INT32)aRect.Bottom();

        if ( !mnGroupLevel )
            AddShape( ESCHER_ShpInst_Min, 5 );                              // Flags: Group | Patriarch
        else
        {
            AddShape( ESCHER_ShpInst_Min, 0x201 );                          // Flags: Group | HaveAnchor
            AddAtom( 8, ESCHER_ClientAnchor );
            PtReplaceOrInsert( ESCHER_Persist_Grouping_Logic | mnGroupLevel, mpOutStrm->Tell() );
            *mpOutStrm << (INT16)aRect.Top() << (INT16)aRect.Left() << (INT16)aRect.Right() << (INT16)aRect.Bottom();
        }
        if ( pClientData )
        {
            pClientData->Seek( STREAM_SEEK_TO_END );
            sal_uInt32 nSize = pClientData->Tell();
            if ( nSize )
            {
                *mpOutStrm << (sal_uInt32)( ( ESCHER_ClientData << 16 ) | 0xf )
                        << nSize;
                mpOutStrm->Write( pClientData->GetData(), nSize );
            }
        }
        CloseContainer();                                               // ESCHER_SpContainer
    }
    mnGroupLevel++;
}

// ---------------------------------------------------------------------------------------------
<|endoftext|>