<commit_before>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "platform/assert.h"
#include "vm/message.h"
#include "vm/unit_test.h"

namespace dart {

// Provide access to private members of MessageQueue for testing.
class MessageQueueTestPeer {
 public:
  explicit MessageQueueTestPeer(MessageQueue* queue) : queue_(queue) {}

  bool HasMessage() const {
    // We don't really need to grab the monitor during the unit test,
    // but it doesn't hurt.
    queue_->monitor_.Enter();
    bool result = (queue_->head_[Message::kNormalPriority] != NULL ||
                   queue_->head_[Message::kOOBPriority] != NULL);
    queue_->monitor_.Exit();
    return result;
  }

 private:
  MessageQueue* queue_;
};

static uint8_t* AllocMsg(const char* str) {
  return reinterpret_cast<uint8_t*>(strdup(str));
}

TEST_CASE(MessageQueue_BasicOperations) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  EXPECT(!queue_peer.HasMessage());

  Dart_Port port = 1;

  // Add two messages.
  Message* msg1 =
      new Message(port, 0, AllocMsg("msg1"), Message::kNormalPriority);
  queue.Enqueue(msg1);
  EXPECT(queue_peer.HasMessage());

  Message* msg2 =
      new Message(port, 0, AllocMsg("msg2"), Message::kNormalPriority);

  queue.Enqueue(msg2);
  EXPECT(queue_peer.HasMessage());

  // Remove two messages.
  Message* msg = queue.Dequeue(0);
  EXPECT(msg != NULL);
  EXPECT_STREQ("msg1", reinterpret_cast<char*>(msg->data()));
  EXPECT(queue_peer.HasMessage());

  msg = queue.Dequeue(0);
  EXPECT(msg != NULL);
  EXPECT_STREQ("msg2", reinterpret_cast<char*>(msg->data()));
  EXPECT(!queue_peer.HasMessage());

  delete msg1;
  delete msg2;
}

TEST_CASE(MessageQueue_Priorities) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  EXPECT(!queue_peer.HasMessage());

  Dart_Port port = 1;

  // Add two messages.
  Message* msg1 =
      new Message(port, 0, AllocMsg("msg1"), Message::kNormalPriority);
  queue.Enqueue(msg1);
  EXPECT(queue_peer.HasMessage());

  Message* msg2 =
      new Message(port, 0, AllocMsg("msg2"), Message::kOOBPriority);

  queue.Enqueue(msg2);
  EXPECT(queue_peer.HasMessage());

  // The higher priority message is delivered first.
  Message* msg = queue.Dequeue(0);
  EXPECT(msg != NULL);
  EXPECT_STREQ("msg2", reinterpret_cast<char*>(msg->data()));
  EXPECT(queue_peer.HasMessage());

  msg = queue.Dequeue(0);
  EXPECT(msg != NULL);
  EXPECT_STREQ("msg1", reinterpret_cast<char*>(msg->data()));
  EXPECT(!queue_peer.HasMessage());

  delete msg1;
  delete msg2;
}

// A thread which receives an expected sequence of messages.
static Monitor* sync = NULL;
static MessageQueue* shared_queue = NULL;
void MessageReceiver_start(uword unused) {
  // We only need an isolate here because the MonitorLocker in the
  // MessageQueue expects it, we don't need to initialize the isolate
  // as it does not run any dart code.
  Dart::CreateIsolate(NULL);

  // Create a message queue and share it.
  MessageQueue* queue = new MessageQueue();
  MessageQueueTestPeer peer(queue);
  shared_queue = queue;

  // Tell the other thread that the shared queue is ready.
  {
    MonitorLocker ml(sync);
    ml.Notify();
  }

  // Wait for the other thread to fill the queue a bit.
  while (!peer.HasMessage()) {
    MonitorLocker ml(sync);
    ml.Wait(5);
  }

  for (int i = 0; i < 3; i++) {
    Message* msg = queue->Dequeue(0);
    EXPECT(msg != NULL);
    EXPECT_EQ(i + 10, msg->dest_port());
    EXPECT_EQ(i + 100, msg->reply_port());
    EXPECT_EQ(i + 1000, *(reinterpret_cast<int*>(msg->data())));
    delete msg;
  }
  for (int i = 0; i < 3; i++) {
    Message* msg = queue->Dequeue(0);
    EXPECT(msg != NULL);
    EXPECT_EQ(i + 20, msg->dest_port());
    EXPECT_EQ(i + 200, msg->reply_port());
    EXPECT_EQ(i + 2000, *(reinterpret_cast<int*>(msg->data())));
    delete msg;
  }
  shared_queue = NULL;
  delete queue;
  Dart::ShutdownIsolate();
}

TEST_CASE(MessageQueue_WaitNotify) {
  sync = new Monitor();

  int result = Thread::Start(MessageReceiver_start, 0);
  EXPECT_EQ(0, result);

  // Wait for the shared queue to be created.
  while (shared_queue == NULL) {
    MonitorLocker ml(sync);
    ml.Wait(5);
  }
  ASSERT(shared_queue != NULL);

  // Pile up three messages before the other thread runs.
  for (int i = 0; i < 3; i++) {
    int* data = reinterpret_cast<int*>(malloc(sizeof(*data)));
    *data = i + 1000;
    Message* msg =
        new Message(i + 10, i + 100, reinterpret_cast<uint8_t*>(data),
                    Message::kNormalPriority);
    shared_queue->Enqueue(msg);
  }

  // Wake the other thread and have it start consuming messages.
  {
    MonitorLocker ml(sync);
    ml.Notify();
  }

  // Add a few more messages after sleeping to allow the other thread
  // to potentially exercise the blocking code path in Dequeue.
  OS::Sleep(5);
  for (int i = 0; i < 3; i++) {
    int* data = reinterpret_cast<int*>(malloc(sizeof(*data)));
    *data = i + 2000;
    Message* msg =
        new Message(i + 20, i + 200, reinterpret_cast<uint8_t*>(data),
                    Message::kNormalPriority);
    shared_queue->Enqueue(msg);
  }

  sync = NULL;
  delete sync;

  // Give the spawned thread enough time to properly exit.
  OS::Sleep(20);
}

TEST_CASE(MessageQueue_FlushAll) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  Dart_Port port1 = 1;
  Dart_Port port2 = 2;

  // Add two messages.
  Message* msg1 =
      new Message(port1, 0, AllocMsg("msg1"), Message::kNormalPriority);
  queue.Enqueue(msg1);
  Message* msg2 =
      new Message(port2, 0, AllocMsg("msg2"), Message::kNormalPriority);
  queue.Enqueue(msg2);

  EXPECT(queue_peer.HasMessage());
  queue.FlushAll();
  EXPECT(!queue_peer.HasMessage());

  // msg1 and msg2 already delete by FlushAll.
}

TEST_CASE(MessageQueue_Flush) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  Dart_Port port1 = 1;
  Dart_Port port2 = 2;

  // Add two messages on different ports.
  Message* msg1 =
      new Message(port1, 0, AllocMsg("msg1"), Message::kNormalPriority);
  queue.Enqueue(msg1);
  Message* msg2 =
      new Message(port2, 0, AllocMsg("msg2"), Message::kNormalPriority);
  queue.Enqueue(msg2);
  EXPECT(queue_peer.HasMessage());

  queue.Flush(port1);

  // One message is left in the queue.
  EXPECT(queue_peer.HasMessage());
  Message* msg = queue.Dequeue(0);
  EXPECT(msg != NULL);
  EXPECT_STREQ("msg2", reinterpret_cast<char*>(msg->data()));

  EXPECT(!queue_peer.HasMessage());

  // msg1 is already deleted by Flush.
  delete msg2;
}

TEST_CASE(MessageQueue_Flush_MultipleMessages) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  Dart_Port port1 = 1;

  Message* msg1 =
      new Message(port1, 0, AllocMsg("msg1"), Message::kNormalPriority);
  queue.Enqueue(msg1);
  Message* msg2 =
      new Message(port1, 0, AllocMsg("msg2"), Message::kNormalPriority);
  queue.Enqueue(msg2);
  EXPECT(queue_peer.HasMessage());

  queue.Flush(port1);

  // Queue is empty.
  EXPECT(!queue_peer.HasMessage());
  // msg1 and msg2 are already deleted by Flush.
}

TEST_CASE(MessageQueue_Flush_EmptyQueue) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  Dart_Port port1 = 1;

  EXPECT(!queue_peer.HasMessage());
  queue.Flush(port1);

  // Queue is still empty.
  EXPECT(!queue_peer.HasMessage());
}

}  // namespace dart
<commit_msg>Fix flaky message queue test.<commit_after>// Copyright (c) 2012, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "platform/assert.h"
#include "vm/message.h"
#include "vm/unit_test.h"

namespace dart {

// Provide access to private members of MessageQueue for testing.
class MessageQueueTestPeer {
 public:
  explicit MessageQueueTestPeer(MessageQueue* queue) : queue_(queue) {}

  bool HasMessage() const {
    // We don't really need to grab the monitor during the unit test,
    // but it doesn't hurt.
    queue_->monitor_.Enter();
    bool result = (queue_->head_[Message::kNormalPriority] != NULL ||
                   queue_->head_[Message::kOOBPriority] != NULL);
    queue_->monitor_.Exit();
    return result;
  }

 private:
  MessageQueue* queue_;
};

static uint8_t* AllocMsg(const char* str) {
  return reinterpret_cast<uint8_t*>(strdup(str));
}

TEST_CASE(MessageQueue_BasicOperations) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  EXPECT(!queue_peer.HasMessage());

  Dart_Port port = 1;

  // Add two messages.
  Message* msg1 =
      new Message(port, 0, AllocMsg("msg1"), Message::kNormalPriority);
  queue.Enqueue(msg1);
  EXPECT(queue_peer.HasMessage());

  Message* msg2 =
      new Message(port, 0, AllocMsg("msg2"), Message::kNormalPriority);

  queue.Enqueue(msg2);
  EXPECT(queue_peer.HasMessage());

  // Remove two messages.
  Message* msg = queue.Dequeue(0);
  EXPECT(msg != NULL);
  EXPECT_STREQ("msg1", reinterpret_cast<char*>(msg->data()));
  EXPECT(queue_peer.HasMessage());

  msg = queue.Dequeue(0);
  EXPECT(msg != NULL);
  EXPECT_STREQ("msg2", reinterpret_cast<char*>(msg->data()));
  EXPECT(!queue_peer.HasMessage());

  delete msg1;
  delete msg2;
}

TEST_CASE(MessageQueue_Priorities) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  EXPECT(!queue_peer.HasMessage());

  Dart_Port port = 1;

  // Add two messages.
  Message* msg1 =
      new Message(port, 0, AllocMsg("msg1"), Message::kNormalPriority);
  queue.Enqueue(msg1);
  EXPECT(queue_peer.HasMessage());

  Message* msg2 =
      new Message(port, 0, AllocMsg("msg2"), Message::kOOBPriority);

  queue.Enqueue(msg2);
  EXPECT(queue_peer.HasMessage());

  // The higher priority message is delivered first.
  Message* msg = queue.Dequeue(0);
  EXPECT(msg != NULL);
  EXPECT_STREQ("msg2", reinterpret_cast<char*>(msg->data()));
  EXPECT(queue_peer.HasMessage());

  msg = queue.Dequeue(0);
  EXPECT(msg != NULL);
  EXPECT_STREQ("msg1", reinterpret_cast<char*>(msg->data()));
  EXPECT(!queue_peer.HasMessage());

  delete msg1;
  delete msg2;
}

// A thread which receives an expected sequence of messages.
static Monitor* sync = NULL;
static MessageQueue* shared_queue = NULL;
void MessageReceiver_start(uword unused) {
  // We only need an isolate here because the MonitorLocker in the
  // MessageQueue expects it, we don't need to initialize the isolate
  // as it does not run any dart code.
  Dart::CreateIsolate(NULL);

  // Create a message queue and share it.
  MessageQueue* queue = new MessageQueue();
  MessageQueueTestPeer peer(queue);
  shared_queue = queue;

  // Tell the other thread that the shared queue is ready.
  {
    MonitorLocker ml(sync);
    ml.Notify();
  }

  // Wait for the other thread to fill the queue a bit.
  while (!peer.HasMessage()) {
    MonitorLocker ml(sync);
    ml.Wait(5);
  }

  int i = 0;
  while (i < 3) {
    Message* msg = queue->Dequeue(0);
    // Dequeue(0) can return NULL due to spurious wakeup.
    if (msg != NULL) {
      EXPECT_EQ(i + 10, msg->dest_port());
      EXPECT_EQ(i + 100, msg->reply_port());
      EXPECT_EQ(i + 1000, *(reinterpret_cast<int*>(msg->data())));
      delete msg;
      i++;
    }
  }

  i = 0;
  while (i < 3) {
    Message* msg = queue->Dequeue(0);
    // Dequeue(0) can return NULL due to spurious wakeup.
    if (msg != NULL) {
      EXPECT_EQ(i + 20, msg->dest_port());
      EXPECT_EQ(i + 200, msg->reply_port());
      EXPECT_EQ(i + 2000, *(reinterpret_cast<int*>(msg->data())));
      delete msg;
      i++;
    }
  }
  shared_queue = NULL;
  delete queue;
  Dart::ShutdownIsolate();
}

TEST_CASE(MessageQueue_WaitNotify) {
  sync = new Monitor();

  int result = Thread::Start(MessageReceiver_start, 0);
  EXPECT_EQ(0, result);

  // Wait for the shared queue to be created.
  while (shared_queue == NULL) {
    MonitorLocker ml(sync);
    ml.Wait(5);
  }
  ASSERT(shared_queue != NULL);

  // Pile up three messages before the other thread runs.
  for (int i = 0; i < 3; i++) {
    int* data = reinterpret_cast<int*>(malloc(sizeof(*data)));
    *data = i + 1000;
    Message* msg =
        new Message(i + 10, i + 100, reinterpret_cast<uint8_t*>(data),
                    Message::kNormalPriority);
    shared_queue->Enqueue(msg);
  }

  // Wake the other thread and have it start consuming messages.
  {
    MonitorLocker ml(sync);
    ml.Notify();
  }

  // Add a few more messages after sleeping to allow the other thread
  // to potentially exercise the blocking code path in Dequeue.
  OS::Sleep(5);
  for (int i = 0; i < 3; i++) {
    int* data = reinterpret_cast<int*>(malloc(sizeof(*data)));
    *data = i + 2000;
    Message* msg =
        new Message(i + 20, i + 200, reinterpret_cast<uint8_t*>(data),
                    Message::kNormalPriority);
    shared_queue->Enqueue(msg);
  }

  sync = NULL;
  delete sync;

  // Give the spawned thread enough time to properly exit.
  OS::Sleep(20);
}

TEST_CASE(MessageQueue_FlushAll) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  Dart_Port port1 = 1;
  Dart_Port port2 = 2;

  // Add two messages.
  Message* msg1 =
      new Message(port1, 0, AllocMsg("msg1"), Message::kNormalPriority);
  queue.Enqueue(msg1);
  Message* msg2 =
      new Message(port2, 0, AllocMsg("msg2"), Message::kNormalPriority);
  queue.Enqueue(msg2);

  EXPECT(queue_peer.HasMessage());
  queue.FlushAll();
  EXPECT(!queue_peer.HasMessage());

  // msg1 and msg2 already delete by FlushAll.
}

TEST_CASE(MessageQueue_Flush) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  Dart_Port port1 = 1;
  Dart_Port port2 = 2;

  // Add two messages on different ports.
  Message* msg1 =
      new Message(port1, 0, AllocMsg("msg1"), Message::kNormalPriority);
  queue.Enqueue(msg1);
  Message* msg2 =
      new Message(port2, 0, AllocMsg("msg2"), Message::kNormalPriority);
  queue.Enqueue(msg2);
  EXPECT(queue_peer.HasMessage());

  queue.Flush(port1);

  // One message is left in the queue.
  EXPECT(queue_peer.HasMessage());
  Message* msg = queue.Dequeue(0);
  EXPECT(msg != NULL);
  EXPECT_STREQ("msg2", reinterpret_cast<char*>(msg->data()));

  EXPECT(!queue_peer.HasMessage());

  // msg1 is already deleted by Flush.
  delete msg2;
}

TEST_CASE(MessageQueue_Flush_MultipleMessages) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  Dart_Port port1 = 1;

  Message* msg1 =
      new Message(port1, 0, AllocMsg("msg1"), Message::kNormalPriority);
  queue.Enqueue(msg1);
  Message* msg2 =
      new Message(port1, 0, AllocMsg("msg2"), Message::kNormalPriority);
  queue.Enqueue(msg2);
  EXPECT(queue_peer.HasMessage());

  queue.Flush(port1);

  // Queue is empty.
  EXPECT(!queue_peer.HasMessage());
  // msg1 and msg2 are already deleted by Flush.
}

TEST_CASE(MessageQueue_Flush_EmptyQueue) {
  MessageQueue queue;
  MessageQueueTestPeer queue_peer(&queue);
  Dart_Port port1 = 1;

  EXPECT(!queue_peer.HasMessage());
  queue.Flush(port1);

  // Queue is still empty.
  EXPECT(!queue_peer.HasMessage());
}

}  // namespace dart
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "ids.hrc"
#include "openlocked.hxx"

OpenLockedQueryBox::OpenLockedQueryBox( Window* pParent, ResMgr* pResMgr, const String& aMessage ) :
    MessBox(pParent, 0,
            String( ResId( STR_OPENLOCKED_TITLE, *pResMgr ) ),
            aMessage )
{
    SetImage( QueryBox::GetStandardImage() );

    AddButton( String( ResId( STR_OPENLOCKED_OPENREADONLY_BTN, *pResMgr ) ), RET_YES,
            BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_OKBUTTON | BUTTONDIALOG_FOCUSBUTTON);

    AddButton( String( ResId( STR_OPENLOCKED_OPENCOPY_BTN, *pResMgr ) ), RET_NO, 0);

    AddButton( BUTTON_CANCEL, RET_CANCEL, BUTTONDIALOG_CANCELBUTTON );
    SetButtonHelpText( RET_YES, String() );
    SetButtonHelpText( RET_NO, String() );
}

OpenLockedQueryBox::~OpenLockedQueryBox()
{
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<commit_msg>bnc#656566: EnableAlwaysOnTop(true) in OpenLockedQueryBox constructor<commit_after>/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2000, 2010 Oracle and/or its affiliates.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org 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 version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/

#include "ids.hrc"
#include "openlocked.hxx"

OpenLockedQueryBox::OpenLockedQueryBox( Window* pParent, ResMgr* pResMgr, const String& aMessage ) :
    MessBox(pParent, 0,
            String( ResId( STR_OPENLOCKED_TITLE, *pResMgr ) ),
            aMessage )
{
    SetImage( QueryBox::GetStandardImage() );

    AddButton( String( ResId( STR_OPENLOCKED_OPENREADONLY_BTN, *pResMgr ) ), RET_YES,
            BUTTONDIALOG_DEFBUTTON | BUTTONDIALOG_OKBUTTON | BUTTONDIALOG_FOCUSBUTTON);

    AddButton( String( ResId( STR_OPENLOCKED_OPENCOPY_BTN, *pResMgr ) ), RET_NO, 0);

    AddButton( BUTTON_CANCEL, RET_CANCEL, BUTTONDIALOG_CANCELBUTTON );
    SetButtonHelpText( RET_YES, String() );
    SetButtonHelpText( RET_NO, String() );

#ifdef WNT
    // bnc#656566
    // Yes, it is silly to do this only for this dialog but not the
    // other similar ones. But hey, it was about this dialog that the
    // customer complained. You who read this and feel the itch, feel
    // free to fix the problem in a better way.
    EnableAlwaysOnTop( true );
#endif
}

OpenLockedQueryBox::~OpenLockedQueryBox()
{
}

/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
<|endoftext|>


<commit_before>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "rpcnetwork.h"
#include "rpcservicepool.h"
#include "oosmanager.h"
#include "rpcsendv1.h"
#include "rpcsendv2.h"
#include "rpctargetpool.h"
#include "rpcnetworkparams.h"
#include <vespa/messagebus/errorcode.h>
#include <vespa/messagebus/iprotocol.h>
#include <vespa/messagebus/tracelevel.h>
#include <vespa/messagebus/emptyreply.h>
#include <vespa/messagebus/routing/routingnode.h>
#include <vespa/slobrok/sbregister.h>
#include <vespa/slobrok/sbmirror.h>
#include <vespa/vespalib/component/vtag.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/threadstackexecutor.h>
#include <vespa/fnet/scheduler.h>
#include <vespa/fnet/transport.h>
#include <vespa/fnet/frt/supervisor.h>

#include <vespa/log/log.h>
LOG_SETUP(".rpcnetwork");

using vespalib::make_string;

namespace {

/**
 * Implements a helper class for {@link RPCNetwork#sync()}. It provides a
 * blocking method {@link #await()} that will wait until the internal state
 * of this object is set to 'done'. By scheduling this task in the network
 * thread and then calling this method, we achieve handshaking with the network
 * thread.
 */
class SyncTask : public FNET_Task {
private:
    vespalib::Gate _gate;

public:
    SyncTask(FNET_Scheduler &s) :
        FNET_Task(&s),
        _gate() {
        ScheduleNow();
    }
    ~SyncTask() {}

    void await() {
        _gate.await();
    }

    void PerformTask() override {
        _gate.countDown();
    }
};

} // namespace <unnamed>

namespace mbus {

RPCNetwork::SendContext::SendContext(RPCNetwork &net, const Message &msg,
                                     const std::vector<RoutingNode*> &recipients)
    : _net(net),
      _msg(msg),
      _traceLevel(msg.getTrace().getLevel()),
      _recipients(recipients),
      _hasError(false),
      _pending(_recipients.size()),
      _version(_net.getVersion())
{ }

void
RPCNetwork::SendContext::handleVersion(const vespalib::Version *version)
{
    bool shouldSend = false;
    {
        vespalib::LockGuard guard(_lock);
        if (version == nullptr) {
            _hasError = true;
        } else if (*version < _version) {
            _version = *version;
        }
        if (--_pending == 0) {
            shouldSend = true;
        }
    }
    if (shouldSend) {
        _net.send(*this);
        delete this;
    }
}

RPCNetwork::TargetPoolTask::TargetPoolTask(FNET_Scheduler &scheduler, RPCTargetPool &pool)
    : FNET_Task(&scheduler),
      _pool(pool)
{
    ScheduleNow();
}

void
RPCNetwork::TargetPoolTask::PerformTask()
{
    _pool.flushTargets(false);
    Schedule(1.0);
}

RPCNetwork::RPCNetwork(const RPCNetworkParams &params) :
    _owner(0),
    _ident(params.getIdentity()),
    _threadPool(std::make_unique<FastOS_ThreadPool>(128000, 0)),
    _transport(std::make_unique<FNET_Transport>()),
    _orb(std::make_unique<FRT_Supervisor>(_transport.get(), nullptr)),
    _scheduler(*_transport->GetScheduler()),
    _targetPool(std::make_unique<RPCTargetPool>(params.getConnectionExpireSecs())),
    _targetPoolTask(_scheduler, *_targetPool),
    _servicePool(std::make_unique<RPCServicePool>(*this, 4096)),
    _slobrokCfgFactory(std::make_unique<slobrok::ConfiguratorFactory>(params.getSlobrokConfig())),
    _mirror(std::make_unique<slobrok::api::MirrorAPI>(*_orb, *_slobrokCfgFactory)),
    _regAPI(std::make_unique<slobrok::api::RegisterAPI>(*_orb, *_slobrokCfgFactory)),
    _oosManager(std::make_unique<OOSManager>(*_orb, *_mirror, params.getOOSServerPattern())),
    _requestedPort(params.getListenPort()),
    _executor(std::make_unique<vespalib::ThreadStackExecutor>(4,65536)),
    _sendV1(std::make_unique<RPCSendV1>()),
    _sendV2(std::make_unique<RPCSendV2>()),
    _sendAdapters(),
    _compressionConfig(params.getCompressionConfig())
{
    _transport->SetDirectWrite(false);
    _transport->SetMaxInputBufferSize(params.getMaxInputBufferSize());
    _transport->SetMaxOutputBufferSize(params.getMaxOutputBufferSize());
}

RPCNetwork::~RPCNetwork()
{
    shutdown();
}

FRT_RPCRequest *
RPCNetwork::allocRequest()
{
    return _orb->AllocRPCRequest();
}

RPCTarget::SP
RPCNetwork::getTarget(const RPCServiceAddress &address)
{
    return _targetPool->getTarget(*_orb, address);
}

void
RPCNetwork::replyError(const SendContext &ctx, uint32_t errCode, const string &errMsg)
{
    for (RoutingNode * rnode : ctx._recipients) {
        Reply::UP reply(new EmptyReply());
        reply->setTrace(Trace(ctx._traceLevel));
        reply->addError(Error(errCode, errMsg));
        _owner->deliverReply(std::move(reply), *rnode);
    }
}

int RPCNetwork::getPort() const { return _orb->GetListenPort(); }

void
RPCNetwork::flushTargetPool()
{
    _targetPool->flushTargets(true);
}

const vespalib::Version &
RPCNetwork::getVersion() const
{
    return vespalib::Vtag::currentVersion;
}

void
RPCNetwork::attach(INetworkOwner &owner)
{
    LOG_ASSERT(_owner == 0);
    _owner = &owner;

    _sendV1->attach(*this);
    _sendV2->attach(*this);
    _sendAdapters[vespalib::Version(5)] = _sendV1.get();
    _sendAdapters[vespalib::Version(6, 149)] = _sendV2.get();

    FRT_ReflectionBuilder builder(_orb.get());
    builder.DefineMethod("mbus.getVersion", "", "s", true, FRT_METHOD(RPCNetwork::invoke), this);
    builder.MethodDesc("Retrieves the message bus version.");
    builder.ReturnDesc("version", "The message bus version.");
}

void
RPCNetwork::invoke(FRT_RPCRequest *req)
{
    req->GetReturn()->AddString(getVersion().toString().c_str());
}

const string
RPCNetwork::getConnectionSpec() const
{
    return make_string("tcp/%s:%d", _ident.getHostname().c_str(), _orb->GetListenPort());
}

RPCSendAdapter *
RPCNetwork::getSendAdapter(const vespalib::Version &version)
{
    if (version < _sendAdapters.begin()->first) {
        return nullptr;
    }
    return (--_sendAdapters.upper_bound(version))->second;
}

bool
RPCNetwork::start()
{
    if (!_orb->Listen(_requestedPort)) {
        return false;
    }
    if (!_transport->Start(_threadPool.get())) {
        return false;
    }
    return true;
}

vespalib::Executor &
RPCNetwork::getExecutor() {
    return *_executor;
}

bool
RPCNetwork::waitUntilReady(double seconds) const
{
    slobrok::api::SlobrokList brokerList;
    slobrok::Configurator::UP configurator = _slobrokCfgFactory->create(brokerList);
    bool hasConfig = false;
    for (uint32_t i = 0; i < seconds * 100; ++i) {
        if (configurator->poll()) {
            hasConfig = true;
        }
        if (_mirror->ready() && _oosManager->isReady()) {
            return true;
        }
        FastOS_Thread::Sleep(10);
    }
    if (! hasConfig) {
        LOG(error, "failed to get config for slobroks in %d seconds", (int)seconds);
    } else if (! _mirror->ready()) {
        std::string brokers = brokerList.logString();
        LOG(error, "mirror (of %s) failed to become ready in %d seconds",
            brokers.c_str(), (int)seconds);
    } else if (! _oosManager->isReady()) {
        LOG(error, "OOS manager failed to become ready in %d seconds", (int)seconds);
    }
    return false;
}

void
RPCNetwork::registerSession(const string &session)
{
    if (_ident.getServicePrefix().size() == 0) {
        LOG(warning, "The session (%s) will not be registered"
            "in the Slobrok since this network has no identity.",
            session.c_str());
        return;
    }
    string name = _ident.getServicePrefix();
    name += "/";
    name += session;
    _regAPI->registerName(name);
}

void
RPCNetwork::unregisterSession(const string &session)
{
    if (_ident.getServicePrefix().size() == 0) {
        return;
    }
    string name = _ident.getServicePrefix();
    name += "/";
    name += session;
    _regAPI->unregisterName(name);
}

bool
RPCNetwork::allocServiceAddress(RoutingNode &recipient)
{
    const Hop &hop = recipient.getRoute().getHop(0);
    string service = hop.getServiceName();
    Error error = resolveServiceAddress(recipient, service);
    if (error.getCode() == ErrorCode::NONE) {
        return true; // service address resolved
    }
    recipient.setError(error);
    return false; // service adddress not resolved
}

Error
RPCNetwork::resolveServiceAddress(RoutingNode &recipient, const string &serviceName)
{
    if (_oosManager->isOOS(serviceName)) {
        return Error(ErrorCode::SERVICE_OOS,
                     make_string("The service '%s' has been marked as out of service.",
                                           serviceName.c_str()));
    }
    RPCServiceAddress::UP ret = _servicePool->resolve(serviceName);
    if (ret.get() == nullptr) {
        return Error(ErrorCode::NO_ADDRESS_FOR_SERVICE,
                     make_string("The address of service '%s' could not be resolved. It is not currently "
                                 "registered with the Vespa name server. "
                                 "The service must be having problems, or the routing configuration is wrong.",
                                 serviceName.c_str()));
    }
    RPCTarget::SP target = _targetPool->getTarget(*_orb, *ret);
    if (target.get() == nullptr) {
        return Error(ErrorCode::CONNECTION_ERROR,
                     make_string("Failed to connect to service '%s'.", serviceName.c_str()));
    }
    ret->setTarget(target); // free by freeServiceAddress()
    recipient.setServiceAddress(IServiceAddress::UP(ret.release()));
    return Error();
}

void
RPCNetwork::freeServiceAddress(RoutingNode &recipient)
{
    recipient.setServiceAddress(IServiceAddress::UP());
}

void
RPCNetwork::send(const Message &msg, const std::vector<RoutingNode*> &recipients)
{
    SendContext &ctx = *(new SendContext(*this, msg, recipients)); // deletes self
    double timeout = ctx._msg.getTimeRemainingNow() / 1000.0;
    for (uint32_t i = 0, len = ctx._recipients.size(); i < len; ++i) {
        RoutingNode *&recipient = ctx._recipients[i];
        LOG_ASSERT(recipient != nullptr);

        RPCServiceAddress &address = static_cast<RPCServiceAddress&>(recipient->getServiceAddress());
        LOG_ASSERT(address.hasTarget());

        address.getTarget().resolveVersion(timeout, ctx);
    }
}

void
RPCNetwork::send(RPCNetwork::SendContext &ctx)
{
    if (ctx._hasError) {
        replyError(ctx, ErrorCode::HANDSHAKE_FAILED, "An error occured while resolving version.");
    } else {
        uint64_t timeRemaining = ctx._msg.getTimeRemainingNow();
        Blob payload = _owner->getProtocol(ctx._msg.getProtocol())->encode(ctx._version, ctx._msg);
        RPCSendAdapter *adapter = getSendAdapter(ctx._version);
        if (adapter == nullptr) {
            replyError(ctx, ErrorCode::INCOMPATIBLE_VERSION,
                       make_string("Can not send to version '%s' recipient.", ctx._version.toString().c_str()));
        } else if (timeRemaining == 0) {
            replyError(ctx, ErrorCode::TIMEOUT,
                       "Aborting transmission because zero time remains.");
        } else if (payload.size() == 0) {
            replyError(ctx, ErrorCode::ENCODE_ERROR,
                       make_string("Protocol '%s' failed to encode message.", ctx._msg.getProtocol().c_str()));
        } else if (ctx._recipients.size() == 1) {
            adapter->sendByHandover(*ctx._recipients.front(), ctx._version, std::move(payload), timeRemaining);
        } else {
            for (auto & recipient : ctx._recipients) {
                adapter->send(*recipient, ctx._version, payload, timeRemaining);
            }
        }
    }
}

void
RPCNetwork::sync()
{
    SyncTask task(_scheduler);
    task.await();
}

void
RPCNetwork::shutdown()
{
    _executor->sync();
    _transport->ShutDown(false);
    _threadPool->Close();
    _executor->shutdown();
    _executor->sync();
}

void
RPCNetwork::postShutdownHook()
{
    _scheduler.CheckTasks();
}

const slobrok::api::IMirrorAPI &
RPCNetwork::getMirror() const
{
    return *_mirror;
}

} // namespace mbus
<commit_msg>Do the sending in a thread pool too.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
#include "rpcnetwork.h"
#include "rpcservicepool.h"
#include "oosmanager.h"
#include "rpcsendv1.h"
#include "rpcsendv2.h"
#include "rpctargetpool.h"
#include "rpcnetworkparams.h"
#include <vespa/messagebus/errorcode.h>
#include <vespa/messagebus/iprotocol.h>
#include <vespa/messagebus/tracelevel.h>
#include <vespa/messagebus/emptyreply.h>
#include <vespa/messagebus/routing/routingnode.h>
#include <vespa/slobrok/sbregister.h>
#include <vespa/slobrok/sbmirror.h>
#include <vespa/vespalib/component/vtag.h>
#include <vespa/vespalib/util/stringfmt.h>
#include <vespa/vespalib/util/lambdatask.h>
#include <vespa/fnet/scheduler.h>
#include <vespa/fnet/transport.h>
#include <vespa/fnet/frt/supervisor.h>

#include <vespa/log/log.h>
LOG_SETUP(".rpcnetwork");

using vespalib::make_string;

namespace {

/**
 * Implements a helper class for {@link RPCNetwork#sync()}. It provides a
 * blocking method {@link #await()} that will wait until the internal state
 * of this object is set to 'done'. By scheduling this task in the network
 * thread and then calling this method, we achieve handshaking with the network
 * thread.
 */
class SyncTask : public FNET_Task {
private:
    vespalib::Gate _gate;

public:
    SyncTask(FNET_Scheduler &s) :
        FNET_Task(&s),
        _gate() {
        ScheduleNow();
    }
    ~SyncTask() {}

    void await() {
        _gate.await();
    }

    void PerformTask() override {
        _gate.countDown();
    }
};

} // namespace <unnamed>

namespace mbus {

RPCNetwork::SendContext::SendContext(RPCNetwork &net, const Message &msg,
                                     const std::vector<RoutingNode*> &recipients)
    : _net(net),
      _msg(msg),
      _traceLevel(msg.getTrace().getLevel()),
      _recipients(recipients),
      _hasError(false),
      _pending(_recipients.size()),
      _version(_net.getVersion())
{ }

void
RPCNetwork::SendContext::handleVersion(const vespalib::Version *version)
{
    bool shouldSend = false;
    {
        vespalib::LockGuard guard(_lock);
        if (version == nullptr) {
            _hasError = true;
        } else if (*version < _version) {
            _version = *version;
        }
        if (--_pending == 0) {
            shouldSend = true;
        }
    }
    if (shouldSend) {
        _net.getExecutor().execute(vespalib::makeLambdaTask([this]() {
            _net.send(*this);
            delete this;
        }));
    }
}

RPCNetwork::TargetPoolTask::TargetPoolTask(FNET_Scheduler &scheduler, RPCTargetPool &pool)
    : FNET_Task(&scheduler),
      _pool(pool)
{
    ScheduleNow();
}

void
RPCNetwork::TargetPoolTask::PerformTask()
{
    _pool.flushTargets(false);
    Schedule(1.0);
}

RPCNetwork::RPCNetwork(const RPCNetworkParams &params) :
    _owner(0),
    _ident(params.getIdentity()),
    _threadPool(std::make_unique<FastOS_ThreadPool>(128000, 0)),
    _transport(std::make_unique<FNET_Transport>()),
    _orb(std::make_unique<FRT_Supervisor>(_transport.get(), nullptr)),
    _scheduler(*_transport->GetScheduler()),
    _targetPool(std::make_unique<RPCTargetPool>(params.getConnectionExpireSecs())),
    _targetPoolTask(_scheduler, *_targetPool),
    _servicePool(std::make_unique<RPCServicePool>(*this, 4096)),
    _slobrokCfgFactory(std::make_unique<slobrok::ConfiguratorFactory>(params.getSlobrokConfig())),
    _mirror(std::make_unique<slobrok::api::MirrorAPI>(*_orb, *_slobrokCfgFactory)),
    _regAPI(std::make_unique<slobrok::api::RegisterAPI>(*_orb, *_slobrokCfgFactory)),
    _oosManager(std::make_unique<OOSManager>(*_orb, *_mirror, params.getOOSServerPattern())),
    _requestedPort(params.getListenPort()),
    _executor(std::make_unique<vespalib::ThreadStackExecutor>(4,65536)),
    _sendV1(std::make_unique<RPCSendV1>()),
    _sendV2(std::make_unique<RPCSendV2>()),
    _sendAdapters(),
    _compressionConfig(params.getCompressionConfig())
{
    _transport->SetDirectWrite(false);
    _transport->SetMaxInputBufferSize(params.getMaxInputBufferSize());
    _transport->SetMaxOutputBufferSize(params.getMaxOutputBufferSize());
}

RPCNetwork::~RPCNetwork()
{
    shutdown();
}

FRT_RPCRequest *
RPCNetwork::allocRequest()
{
    return _orb->AllocRPCRequest();
}

RPCTarget::SP
RPCNetwork::getTarget(const RPCServiceAddress &address)
{
    return _targetPool->getTarget(*_orb, address);
}

void
RPCNetwork::replyError(const SendContext &ctx, uint32_t errCode, const string &errMsg)
{
    for (RoutingNode * rnode : ctx._recipients) {
        Reply::UP reply(new EmptyReply());
        reply->setTrace(Trace(ctx._traceLevel));
        reply->addError(Error(errCode, errMsg));
        _owner->deliverReply(std::move(reply), *rnode);
    }
}

int RPCNetwork::getPort() const { return _orb->GetListenPort(); }

void
RPCNetwork::flushTargetPool()
{
    _targetPool->flushTargets(true);
}

const vespalib::Version &
RPCNetwork::getVersion() const
{
    return vespalib::Vtag::currentVersion;
}

void
RPCNetwork::attach(INetworkOwner &owner)
{
    LOG_ASSERT(_owner == 0);
    _owner = &owner;

    _sendV1->attach(*this);
    _sendV2->attach(*this);
    _sendAdapters[vespalib::Version(5)] = _sendV1.get();
    _sendAdapters[vespalib::Version(6, 149)] = _sendV2.get();

    FRT_ReflectionBuilder builder(_orb.get());
    builder.DefineMethod("mbus.getVersion", "", "s", true, FRT_METHOD(RPCNetwork::invoke), this);
    builder.MethodDesc("Retrieves the message bus version.");
    builder.ReturnDesc("version", "The message bus version.");
}

void
RPCNetwork::invoke(FRT_RPCRequest *req)
{
    req->GetReturn()->AddString(getVersion().toString().c_str());
}

const string
RPCNetwork::getConnectionSpec() const
{
    return make_string("tcp/%s:%d", _ident.getHostname().c_str(), _orb->GetListenPort());
}

RPCSendAdapter *
RPCNetwork::getSendAdapter(const vespalib::Version &version)
{
    if (version < _sendAdapters.begin()->first) {
        return nullptr;
    }
    return (--_sendAdapters.upper_bound(version))->second;
}

bool
RPCNetwork::start()
{
    if (!_orb->Listen(_requestedPort)) {
        return false;
    }
    if (!_transport->Start(_threadPool.get())) {
        return false;
    }
    return true;
}

vespalib::Executor &
RPCNetwork::getExecutor() {
    return *_executor;
}

bool
RPCNetwork::waitUntilReady(double seconds) const
{
    slobrok::api::SlobrokList brokerList;
    slobrok::Configurator::UP configurator = _slobrokCfgFactory->create(brokerList);
    bool hasConfig = false;
    for (uint32_t i = 0; i < seconds * 100; ++i) {
        if (configurator->poll()) {
            hasConfig = true;
        }
        if (_mirror->ready() && _oosManager->isReady()) {
            return true;
        }
        FastOS_Thread::Sleep(10);
    }
    if (! hasConfig) {
        LOG(error, "failed to get config for slobroks in %d seconds", (int)seconds);
    } else if (! _mirror->ready()) {
        std::string brokers = brokerList.logString();
        LOG(error, "mirror (of %s) failed to become ready in %d seconds",
            brokers.c_str(), (int)seconds);
    } else if (! _oosManager->isReady()) {
        LOG(error, "OOS manager failed to become ready in %d seconds", (int)seconds);
    }
    return false;
}

void
RPCNetwork::registerSession(const string &session)
{
    if (_ident.getServicePrefix().size() == 0) {
        LOG(warning, "The session (%s) will not be registered"
            "in the Slobrok since this network has no identity.",
            session.c_str());
        return;
    }
    string name = _ident.getServicePrefix();
    name += "/";
    name += session;
    _regAPI->registerName(name);
}

void
RPCNetwork::unregisterSession(const string &session)
{
    if (_ident.getServicePrefix().size() == 0) {
        return;
    }
    string name = _ident.getServicePrefix();
    name += "/";
    name += session;
    _regAPI->unregisterName(name);
}

bool
RPCNetwork::allocServiceAddress(RoutingNode &recipient)
{
    const Hop &hop = recipient.getRoute().getHop(0);
    string service = hop.getServiceName();
    Error error = resolveServiceAddress(recipient, service);
    if (error.getCode() == ErrorCode::NONE) {
        return true; // service address resolved
    }
    recipient.setError(error);
    return false; // service adddress not resolved
}

Error
RPCNetwork::resolveServiceAddress(RoutingNode &recipient, const string &serviceName)
{
    if (_oosManager->isOOS(serviceName)) {
        return Error(ErrorCode::SERVICE_OOS,
                     make_string("The service '%s' has been marked as out of service.",
                                           serviceName.c_str()));
    }
    RPCServiceAddress::UP ret = _servicePool->resolve(serviceName);
    if (ret.get() == nullptr) {
        return Error(ErrorCode::NO_ADDRESS_FOR_SERVICE,
                     make_string("The address of service '%s' could not be resolved. It is not currently "
                                 "registered with the Vespa name server. "
                                 "The service must be having problems, or the routing configuration is wrong.",
                                 serviceName.c_str()));
    }
    RPCTarget::SP target = _targetPool->getTarget(*_orb, *ret);
    if (target.get() == nullptr) {
        return Error(ErrorCode::CONNECTION_ERROR,
                     make_string("Failed to connect to service '%s'.", serviceName.c_str()));
    }
    ret->setTarget(target); // free by freeServiceAddress()
    recipient.setServiceAddress(IServiceAddress::UP(ret.release()));
    return Error();
}

void
RPCNetwork::freeServiceAddress(RoutingNode &recipient)
{
    recipient.setServiceAddress(IServiceAddress::UP());
}

void
RPCNetwork::send(const Message &msg, const std::vector<RoutingNode*> &recipients)
{
    SendContext &ctx = *(new SendContext(*this, msg, recipients)); // deletes self
    double timeout = ctx._msg.getTimeRemainingNow() / 1000.0;
    for (uint32_t i = 0, len = ctx._recipients.size(); i < len; ++i) {
        RoutingNode *&recipient = ctx._recipients[i];
        LOG_ASSERT(recipient != nullptr);

        RPCServiceAddress &address = static_cast<RPCServiceAddress&>(recipient->getServiceAddress());
        LOG_ASSERT(address.hasTarget());

        address.getTarget().resolveVersion(timeout, ctx);
    }
}

void
RPCNetwork::send(RPCNetwork::SendContext &ctx)
{
    if (ctx._hasError) {
        replyError(ctx, ErrorCode::HANDSHAKE_FAILED, "An error occured while resolving version.");
    } else {
        uint64_t timeRemaining = ctx._msg.getTimeRemainingNow();
        Blob payload = _owner->getProtocol(ctx._msg.getProtocol())->encode(ctx._version, ctx._msg);
        RPCSendAdapter *adapter = getSendAdapter(ctx._version);
        if (adapter == nullptr) {
            replyError(ctx, ErrorCode::INCOMPATIBLE_VERSION,
                       make_string("Can not send to version '%s' recipient.", ctx._version.toString().c_str()));
        } else if (timeRemaining == 0) {
            replyError(ctx, ErrorCode::TIMEOUT,
                       "Aborting transmission because zero time remains.");
        } else if (payload.size() == 0) {
            replyError(ctx, ErrorCode::ENCODE_ERROR,
                       make_string("Protocol '%s' failed to encode message.", ctx._msg.getProtocol().c_str()));
        } else if (ctx._recipients.size() == 1) {
            adapter->sendByHandover(*ctx._recipients.front(), ctx._version, std::move(payload), timeRemaining);
        } else {
            for (auto & recipient : ctx._recipients) {
                adapter->send(*recipient, ctx._version, payload, timeRemaining);
            }
        }
    }
}

void
RPCNetwork::sync()
{
    SyncTask task(_scheduler);
    task.await();
}

void
RPCNetwork::shutdown()
{
    _executor->sync();
    _transport->ShutDown(false);
    _threadPool->Close();
    _executor->shutdown();
    _executor->sync();
}

void
RPCNetwork::postShutdownHook()
{
    _scheduler.CheckTasks();
}

const slobrok::api::IMirrorAPI &
RPCNetwork::getMirror() const
{
    return *_mirror;
}

} // namespace mbus
<|endoftext|>


<commit_before>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU General Public License as published by the Free  *
* Software Foundation; either version 2 of the License, or (at your option)   *
* any later version.                                                          *
*                                                                             *
* This program 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 General Public License for    *
* more details.                                                               *
*                                                                             *
* You should have received a copy of the GNU General Public License along     *
* with this program; if not, write to the Free Software Foundation, Inc., 51  *
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
*******************************************************************************
*                            SOFA :: Applications                             *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/

#include <SofaSimpleFem/TetrahedronFEMForceField.h>
#include <SofaTest/ForceField_test.h>

namespace sofa {

using namespace modeling;

/**  Test suite for TetrahedronFEMForceField.
  */
template <typename _TetrahedronFEMForceField>
struct TetrahedronFEMForceField_test : public ForceField_test<_TetrahedronFEMForceField>
{

    typedef _TetrahedronFEMForceField ForceType;
    typedef ForceField_test<_TetrahedronFEMForceField> Inherited;
    typedef typename ForceType::DataTypes DataTypes;

    typedef typename ForceType::VecCoord VecCoord;
    typedef typename ForceType::VecDeriv VecDeriv;
    typedef typename ForceType::Coord Coord;
    typedef typename ForceType::Deriv Deriv;
    typedef typename Coord::value_type Real;
    typedef defaulttype::Vec<3,Real> Vec3;

    typedef ForceType Spring;
    typedef component::container::MechanicalObject<DataTypes> DOF;

    VecCoord x;
    VecDeriv v,f;

    /** @name Test_Cases
      For each of these cases, we check if the accurate forces are computed
    */
    TetrahedronFEMForceField_test():Inherited::ForceField_test(std::string(SOFASIMPLEFEM_TEST_SCENES_DIR) + "/" + "TetrahedronFEMForceFieldRegularTetra.scn")
    {
        //Position
        x.resize(4);
        DataTypes::set( x[0], 0,0,0);
        DataTypes::set( x[1], 1,0,0);
        DataTypes::set( x[2], (Real)0.5, (Real)0.8660254037, (Real)0);
        //DataTypes::set( x[3], (SReal)0.5, (SReal)0.28867,(SReal)1.632993);
        DataTypes::set( x[3], (Real)0.5, (Real)0.28867513,(Real)2);
        //Velocity
        v.resize(4);
        DataTypes::set( v[0], 0,0,0);
        DataTypes::set( v[1], 0,0,0);
        DataTypes::set( v[2], 0,0,0);
        DataTypes::set( v[3], 0,0,0);

        //Force e*E*S*1/3  = 1*40*sqrt(3)/4*1/3
        f.resize(4);
        Vec3 fup(0,0,std::sqrt(3.f)*10.0/3.0);
        Vec3 fdown(0,0,std::sqrt(3.f)*10.0/9.0);
        DataTypes::set( f[0],  fdown[0], fdown[1], (Real)fdown[2]);
        DataTypes::set( f[1],  fdown[0], fdown[1], (Real)fdown[2]);
        DataTypes::set( f[2],  fdown[0], fdown[1], (Real)fdown[2]);
        DataTypes::set( f[3],  -fup[0], -fup[1], -(Real)fup[2]);

        // Set force parameters
        Inherited::force->_poissonRatio.setValue(0);
        vector<Real> youngModulusVec;youngModulusVec.push_back(40);
        Inherited::force->_youngModulus.setValue(youngModulusVec);
        Inherited::force->f_method.setValue("small");

        // Init simulation
        sofa::simulation::getSimulation()->init(Inherited::node.get());
    }

    //Test the value of the force it should be equal for each vertex to Pressure*area/4
    void test_valueForce()
    {
        // run the forcefield_test
        Inherited::run_test( x, v, f );
    }
};

// ========= Define the list of types to instanciate.
//using testing::Types;
typedef testing::Types<
component::forcefield::TetrahedronFEMForceField<defaulttype::Vec3Types>
> TestTypes; // the types to instanciate.

// ========= Tests to run for each instanciated type
TYPED_TEST_CASE(TetrahedronFEMForceField_test, TestTypes);

// test case
TYPED_TEST( TetrahedronFEMForceField_test , extension )
{
    this->errorMax *= 1e6;
    this->deltaRange = std::make_pair( 1, this->errorMax * 10 );
    this->debug = false;

    // Young modulus, poisson ratio method

    // run test
    this->test_valueForce();
}

} // namespace sofa
<commit_msg>SofaSimpleFem: Fix test failure<commit_after>/******************************************************************************
*       SOFA, Simulation Open-Framework Architecture, version 1.0 RC 1        *
*                (c) 2006-2011 INRIA, USTL, UJF, CNRS, MGH                    *
*                                                                             *
* This program is free software; you can redistribute it and/or modify it     *
* under the terms of the GNU General Public License as published by the Free  *
* Software Foundation; either version 2 of the License, or (at your option)   *
* any later version.                                                          *
*                                                                             *
* This program 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 General Public License for    *
* more details.                                                               *
*                                                                             *
* You should have received a copy of the GNU General Public License along     *
* with this program; if not, write to the Free Software Foundation, Inc., 51  *
* Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.                   *
*******************************************************************************
*                            SOFA :: Applications                             *
*                                                                             *
* Authors: The SOFA Team and external contributors (see Authors.txt)          *
*                                                                             *
* Contact information: contact@sofa-framework.org                             *
******************************************************************************/

#include <SofaSimpleFem/TetrahedronFEMForceField.h>
#include <SofaTest/ForceField_test.h>

namespace sofa {

using namespace modeling;

/**  Test suite for TetrahedronFEMForceField.
  */
template <typename _TetrahedronFEMForceField>
struct TetrahedronFEMForceField_test : public ForceField_test<_TetrahedronFEMForceField>
{

    typedef _TetrahedronFEMForceField ForceType;
    typedef ForceField_test<_TetrahedronFEMForceField> Inherited;
    typedef typename ForceType::DataTypes DataTypes;

    typedef typename ForceType::VecCoord VecCoord;
    typedef typename ForceType::VecDeriv VecDeriv;
    typedef typename ForceType::Coord Coord;
    typedef typename ForceType::Deriv Deriv;
    typedef typename Coord::value_type Real;
    typedef defaulttype::Vec<3,Real> Vec3;

    typedef ForceType Spring;
    typedef component::container::MechanicalObject<DataTypes> DOF;

    VecCoord x;
    VecDeriv v,f;

    /** @name Test_Cases
      For each of these cases, we check if the accurate forces are computed
    */
    TetrahedronFEMForceField_test():Inherited::ForceField_test(std::string(SOFASIMPLEFEM_TEST_SCENES_DIR) + "/" + "TetrahedronFEMForceFieldRegularTetra.scn")
    {
        //Position
        x.resize(4);
        DataTypes::set( x[0], 0,0,0);
        DataTypes::set( x[1], 1,0,0);
        DataTypes::set( x[2], (Real)0.5, (Real)0.8660254037, (Real)0);
        //DataTypes::set( x[3], (SReal)0.5, (SReal)0.28867,(SReal)1.632993);
        DataTypes::set( x[3], (Real)0.5, (Real)0.28867513,(Real)2);
        //Velocity
        v.resize(4);
        DataTypes::set( v[0], 0,0,0);
        DataTypes::set( v[1], 0,0,0);
        DataTypes::set( v[2], 0,0,0);
        DataTypes::set( v[3], 0,0,0);

        //Force e*E*S*1/3  = 1*40*sqrt(3)/4*1/3
        f.resize(4);
        Vec3 fup(0,0,std::sqrt(3.)*10.0/3.0);
        Vec3 fdown(0,0,std::sqrt(3.)*10.0/9.0);
        DataTypes::set( f[0],  fdown[0], fdown[1], (Real)fdown[2]);
        DataTypes::set( f[1],  fdown[0], fdown[1], (Real)fdown[2]);
        DataTypes::set( f[2],  fdown[0], fdown[1], (Real)fdown[2]);
        DataTypes::set( f[3],  -fup[0], -fup[1], -(Real)fup[2]);

        // Set force parameters
        Inherited::force->_poissonRatio.setValue(0);
        vector<Real> youngModulusVec;youngModulusVec.push_back(40);
        Inherited::force->_youngModulus.setValue(youngModulusVec);
        Inherited::force->f_method.setValue("small");

        // Init simulation
        sofa::simulation::getSimulation()->init(Inherited::node.get());
    }

    //Test the value of the force it should be equal for each vertex to Pressure*area/4
    void test_valueForce()
    {
        // run the forcefield_test
        Inherited::run_test( x, v, f );
    }
};

// ========= Define the list of types to instanciate.
//using testing::Types;
typedef testing::Types<
component::forcefield::TetrahedronFEMForceField<defaulttype::Vec3Types>
> TestTypes; // the types to instanciate.

// ========= Tests to run for each instanciated type
TYPED_TEST_CASE(TetrahedronFEMForceField_test, TestTypes);

// test case
TYPED_TEST( TetrahedronFEMForceField_test , extension )
{
    this->errorMax *= 1e6;
    this->deltaRange = std::make_pair( 1, this->errorMax * 10 );
    this->debug = false;

    // Young modulus, poisson ratio method

    // run test
    this->test_valueForce();
}

} // namespace sofa
<|endoftext|>


<commit_before>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 1885
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<commit_msg>P4 to Git Change 1187585 by johtaylo@johtaylo-JTBUILDER03-increment on 2015/09/03 03:00:11<commit_after>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 1886
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<|endoftext|>


<commit_before>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
#define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif  // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
#define AMD_PLATFORM_BUILD_NUMBER 2856
#endif  // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
#define AMD_PLATFORM_REVISION_NUMBER 0
#endif  // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
#define AMD_PLATFORM_RELEASE_INFO
#endif  // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING                                                                           \
  XSTR(AMD_PLATFORM_BUILD_NUMBER)                                                                  \
  "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
#define AMD_PLATFORM_INFO                                                                          \
  "AMD-APP" AMD_PLATFORM_RELEASE_INFO DEBUG_ONLY(                                                  \
      "." IF(IS_OPTIMIZED, "opt", "dbg")) " (" AMD_BUILD_STRING ")"
#endif  // ATI_PLATFORM_INFO

#endif  // VERSIONS_HPP_
<commit_msg>P4 to Git Change 1758765 by chui@ocl-promo-incrementor on 2019/03/20 03:00:33<commit_after>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
#define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif  // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
#define AMD_PLATFORM_BUILD_NUMBER 2857
#endif  // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
#define AMD_PLATFORM_REVISION_NUMBER 0
#endif  // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
#define AMD_PLATFORM_RELEASE_INFO
#endif  // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING                                                                           \
  XSTR(AMD_PLATFORM_BUILD_NUMBER)                                                                  \
  "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
#define AMD_PLATFORM_INFO                                                                          \
  "AMD-APP" AMD_PLATFORM_RELEASE_INFO DEBUG_ONLY(                                                  \
      "." IF(IS_OPTIMIZED, "opt", "dbg")) " (" AMD_BUILD_STRING ")"
#endif  // ATI_PLATFORM_INFO

#endif  // VERSIONS_HPP_
<|endoftext|>


<commit_before>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 1971
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<commit_msg>P4 to Git Change 1220288 by johtaylo@johtaylo-JTBUILDER03-increment on 2015/12/12 03:00:13<commit_after>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
# define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
# define AMD_PLATFORM_BUILD_NUMBER 1972
#endif // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
# define AMD_PLATFORM_REVISION_NUMBER 0
#endif // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
# define AMD_PLATFORM_RELEASE_INFO
#endif // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING XSTR(AMD_PLATFORM_BUILD_NUMBER) \
    "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
# define AMD_PLATFORM_INFO "AMD-APP" AMD_PLATFORM_RELEASE_INFO \
    DEBUG_ONLY("." IF(IS_OPTIMIZED,"opt","dbg")) " (" AMD_BUILD_STRING ")"
#endif // ATI_PLATFORM_INFO

#endif // VERSIONS_HPP_
<|endoftext|>


<commit_before>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
#define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif  // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
#define AMD_PLATFORM_BUILD_NUMBER 2428
#endif  // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
#define AMD_PLATFORM_REVISION_NUMBER 0
#endif  // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
#define AMD_PLATFORM_RELEASE_INFO
#endif  // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING                                                                           \
  XSTR(AMD_PLATFORM_BUILD_NUMBER)                                                                  \
  "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
#define AMD_PLATFORM_INFO                                                                          \
  "AMD-APP" AMD_PLATFORM_RELEASE_INFO DEBUG_ONLY(                                                  \
      "." IF(IS_OPTIMIZED, "opt", "dbg")) " (" AMD_BUILD_STRING ")"
#endif  // ATI_PLATFORM_INFO

#endif  // VERSIONS_HPP_
<commit_msg>P4 to Git Change 1414622 by johtaylo@johtaylo-jtincrementor-increment on 2017/05/26 03:00:05<commit_after>//
// Copyright (c) 2010 Advanced Micro Devices, Inc. All rights reserved.
//

#ifndef VERSIONS_HPP_
#define VERSIONS_HPP_

#include "utils/macros.hpp"

#ifndef AMD_PLATFORM_NAME
#define AMD_PLATFORM_NAME "AMD Accelerated Parallel Processing"
#endif  // AMD_PLATFORM_NAME

#ifndef AMD_PLATFORM_BUILD_NUMBER
#define AMD_PLATFORM_BUILD_NUMBER 2429
#endif  // AMD_PLATFORM_BUILD_NUMBER

#ifndef AMD_PLATFORM_REVISION_NUMBER
#define AMD_PLATFORM_REVISION_NUMBER 0
#endif  // AMD_PLATFORM_REVISION_NUMBER

#ifndef AMD_PLATFORM_RELEASE_INFO
#define AMD_PLATFORM_RELEASE_INFO
#endif  // AMD_PLATFORM_RELEASE_INFO

#define AMD_BUILD_STRING                                                                           \
  XSTR(AMD_PLATFORM_BUILD_NUMBER)                                                                  \
  "." XSTR(AMD_PLATFORM_REVISION_NUMBER)

#ifndef AMD_PLATFORM_INFO
#define AMD_PLATFORM_INFO                                                                          \
  "AMD-APP" AMD_PLATFORM_RELEASE_INFO DEBUG_ONLY(                                                  \
      "." IF(IS_OPTIMIZED, "opt", "dbg")) " (" AMD_BUILD_STRING ")"
#endif  // ATI_PLATFORM_INFO

#endif  // VERSIONS_HPP_
<|endoftext|>


<commit_before>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

// mapnik
#include <mapnik/agg_renderer.hpp>

// agg
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"

namespace mapnik {

template <typename T>
void agg_renderer<T>::process(glyph_symbolizer const& sym,
                              Feature const& feature,
                              proj_transform const& prj_trans)
{
    face_set_ptr faces = font_manager_.get_face_set(sym.get_face_name());
    stroker_ptr strk = font_manager_.get_stroker();
    if (faces->size() > 0 && strk)
    {
        // Get x and y from geometry and translate to pixmap coords.
        double x, y, z=0.0;
        feature.get_geometry(0).label_position(&x, &y);
        prj_trans.backward(x,y,z);
        t_.forward(&x, &y);

        text_renderer<T> ren(pixmap_, faces, *strk);

        // set fill and halo colors
        color fill = sym.eval_color(feature);
        ren.set_fill(fill);
        if (fill != color("transparent")) {
            ren.set_halo_fill(sym.get_halo_fill());
            ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);
        }

        // set font size
        unsigned size = sym.eval_size(feature);
        ren.set_pixel_size(size * scale_factor_);
        faces->set_pixel_sizes(size * scale_factor_);

        // Get and render text path
        //
        text_path_ptr path = sym.get_text_path(faces, feature);
        // apply displacement
        position pos = sym.get_displacement();
        double dx = boost::get<0>(pos);
        double dy = boost::get<1>(pos);
        path->starting_x = x = x+dx;
        path->starting_y = y = y+dy;

        // Prepare glyphs to set internal state and calculate the marker's
        // final box so we can check for a valid placement
        box2d<double> dim = ren.prepare_glyphs(path.get());
        double bsize = (dim.width()>dim.height()?dim.width():dim.height())/2;
        box2d<double> ext(
            floor(x-bsize), floor(y-bsize), ceil(x+bsize), ceil(y+bsize)
            );
        if ((sym.get_allow_overlap() || detector_.has_placement(ext)) &&
            (!sym.get_avoid_edges() || detector_.extent().contains(ext)))
        {
            // Placement is valid, render glyph and update detector.
            ren.render(x, y);
            detector_.insert(ext);
            metawriter_with_properties writer = sym.get_metawriter();
            if (writer.first) writer.first->add_box(ext, feature, t_, writer.second);
        }
    }
    else
    {
        throw config_error(
            "Unable to find specified font face in GlyphSymbolizer"
            );
    }
}
template void agg_renderer<image_32>::process(glyph_symbolizer const&,
                                              Feature const&,
                                              proj_transform const&);
}
<commit_msg>Calculate exact bounding boxes for GlyphSymbolizer.<commit_after>/*****************************************************************************
 *
 * This file is part of Mapnik (c++ mapping toolkit)
 *
 * Copyright (C) 2010 Artem Pavlenko
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * 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., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
 *
 *****************************************************************************/
//$Id$

// mapnik
#include <mapnik/agg_renderer.hpp>

// agg
#include "agg_basics.h"
#include "agg_rendering_buffer.h"
#include "agg_pixfmt_rgba.h"
#include "agg_rasterizer_scanline_aa.h"
#include "agg_scanline_u.h"

namespace mapnik {

template <typename T>
void agg_renderer<T>::process(glyph_symbolizer const& sym,
                              Feature const& feature,
                              proj_transform const& prj_trans)
{
    face_set_ptr faces = font_manager_.get_face_set(sym.get_face_name());
    stroker_ptr strk = font_manager_.get_stroker();
    if (faces->size() > 0 && strk)
    {
        // Get x and y from geometry and translate to pixmap coords.
        double x, y, z=0.0;
        feature.get_geometry(0).label_position(&x, &y);
        prj_trans.backward(x,y,z);
        t_.forward(&x, &y);

        text_renderer<T> ren(pixmap_, faces, *strk);

        // set fill and halo colors
        color fill = sym.eval_color(feature);
        ren.set_fill(fill);
        if (fill != color("transparent")) {
            ren.set_halo_fill(sym.get_halo_fill());
            ren.set_halo_radius(sym.get_halo_radius() * scale_factor_);
        }

        // set font size
        unsigned size = sym.eval_size(feature);
        ren.set_pixel_size(size * scale_factor_);
        faces->set_pixel_sizes(size * scale_factor_);

        // Get and render text path
        //
        text_path_ptr path = sym.get_text_path(faces, feature);
        // apply displacement
        position pos = sym.get_displacement();
        double dx = boost::get<0>(pos);
        double dy = boost::get<1>(pos);
        path->starting_x = x = x+dx;
        path->starting_y = y = y+dy;

        // Prepare glyphs to set internal state and calculate the marker's
        // final box so we can check for a valid placement
        box2d<double> dim = ren.prepare_glyphs(path.get());
        box2d<double> ext(x-dim.width()/2, y-dim.height()/2, x+dim.width()/2, y+dim.height()/2);
        if ((sym.get_allow_overlap() || detector_.has_placement(ext)) &&
            (!sym.get_avoid_edges() || detector_.extent().contains(ext)))
        {
            // Placement is valid, render glyph and update detector.
            ren.render(x, y);
            detector_.insert(ext);
            metawriter_with_properties writer = sym.get_metawriter();
            if (writer.first) writer.first->add_box(ext, feature, t_, writer.second);
        }
    }
    else
    {
        throw config_error(
            "Unable to find specified font face in GlyphSymbolizer"
            );
    }
}
template void agg_renderer<image_32>::process(glyph_symbolizer const&,
                                              Feature const&,
                                              proj_transform const&);
}
<|endoftext|>


<commit_before>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/browser/dom_storage/dom_storage_host.h"

#include "url/gurl.h"
#include "webkit/browser/dom_storage/dom_storage_area.h"
#include "webkit/browser/dom_storage/dom_storage_context.h"
#include "webkit/browser/dom_storage/dom_storage_namespace.h"
#include "webkit/common/dom_storage/dom_storage_types.h"

namespace dom_storage {

DomStorageHost::DomStorageHost(DomStorageContext* context)
    : context_(context) {
}

DomStorageHost::~DomStorageHost() {
  AreaMap::const_iterator it = connections_.begin();
  for (; it != connections_.end(); ++it)
    it->second.namespace_->CloseStorageArea(it->second.area_.get());
  connections_.clear();  // Clear prior to releasing the context_
}

bool DomStorageHost::OpenStorageArea(int connection_id, int namespace_id,
                                     const GURL& origin) {
  DCHECK(!GetOpenArea(connection_id));
  if (GetOpenArea(connection_id))
    return false;  // Indicates the renderer gave us very bad data.
  NamespaceAndArea references;
  references.namespace_ = context_->GetStorageNamespace(namespace_id);
  if (!references.namespace_.get()) {
    // TODO(michaeln): Fix crbug/134003 and return false here.
    // Until then return true to avoid crashing the renderer for
    // sending a bad message.
    return true;
  }
  references.area_ = references.namespace_->OpenStorageArea(origin);
  DCHECK(references.area_.get());
  connections_[connection_id] = references;
  return true;
}

void DomStorageHost::CloseStorageArea(int connection_id) {
  AreaMap::iterator found = connections_.find(connection_id);
  if (found == connections_.end())
    return;
  found->second.namespace_->CloseStorageArea(found->second.area_.get());
  connections_.erase(found);
}

bool DomStorageHost::ExtractAreaValues(
    int connection_id, ValuesMap* map) {
  map->clear();
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area) {
    // TODO(michaeln): Fix crbug/134003 and return false here.
    // Until then return true to avoid crashing the renderer
    // for sending a bad message.
    return true;
  }
  if (!area->IsLoadedInMemory()) {
    DomStorageNamespace* ns = GetNamespace(connection_id);
    DCHECK(ns);
    if (ns->CountInMemoryAreas() > kMaxInMemoryAreas) {
      ns->PurgeMemory(DomStorageNamespace::PURGE_UNOPENED);
      if (ns->CountInMemoryAreas() > kMaxInMemoryAreas)
        ns->PurgeMemory(DomStorageNamespace::PURGE_AGGRESSIVE);
    }
  }
  area->ExtractValues(map);
  return true;
}

unsigned DomStorageHost::GetAreaLength(int connection_id) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return 0;
  return area->Length();
}

base::NullableString16 DomStorageHost::GetAreaKey(int connection_id,
                                                  unsigned index) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return base::NullableString16();
  return area->Key(index);
}

base::NullableString16 DomStorageHost::GetAreaItem(int connection_id,
                                                   const base::string16& key) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return base::NullableString16();
  return area->GetItem(key);
}

bool DomStorageHost::SetAreaItem(
    int connection_id, const base::string16& key,
    const base::string16& value, const GURL& page_url,
    base::NullableString16* old_value) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area) {
    // TODO(michaeln): Fix crbug/134003 and return false here.
    // Until then return true to allow the renderer to operate
    // to a limited degree out of its cache.
    return true;
  }
  if (!area->SetItem(key, value, old_value))
    return false;
  if (old_value->is_null() || old_value->string() != value)
    context_->NotifyItemSet(area, key, value, *old_value, page_url);
  return true;
}

bool DomStorageHost::RemoveAreaItem(
    int connection_id, const base::string16& key, const GURL& page_url,
    base::string16* old_value) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return false;
  if (!area->RemoveItem(key, old_value))
    return false;
  context_->NotifyItemRemoved(area, key, *old_value, page_url);
  return true;
}

bool DomStorageHost::ClearArea(int connection_id, const GURL& page_url) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return false;
  if (!area->Clear())
    return false;
  context_->NotifyAreaCleared(area, page_url);
  return true;
}

bool DomStorageHost::HasAreaOpen(
    int namespace_id, const GURL& origin) const {
  AreaMap::const_iterator it = connections_.begin();
  for (; it != connections_.end(); ++it) {
    if (namespace_id == it->second.namespace_->namespace_id() &&
        origin == it->second.area_->origin()) {
      return true;
    }
  }
  return false;
}

DomStorageArea* DomStorageHost::GetOpenArea(int connection_id) {
  AreaMap::iterator found = connections_.find(connection_id);
  if (found == connections_.end())
    return NULL;
  return found->second.area_.get();
}

DomStorageNamespace* DomStorageHost::GetNamespace(int connection_id) {
  AreaMap::iterator found = connections_.find(connection_id);
  if (found == connections_.end())
    return NULL;
  return found->second.namespace_.get();
}

// NamespaceAndArea

DomStorageHost::NamespaceAndArea::NamespaceAndArea() {}
DomStorageHost::NamespaceAndArea::~NamespaceAndArea() {}

}  // namespace dom_storage
<commit_msg>Undo band-aid which was ignoring wrong SessionStorage association.<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "webkit/browser/dom_storage/dom_storage_host.h"

#include "url/gurl.h"
#include "webkit/browser/dom_storage/dom_storage_area.h"
#include "webkit/browser/dom_storage/dom_storage_context.h"
#include "webkit/browser/dom_storage/dom_storage_namespace.h"
#include "webkit/common/dom_storage/dom_storage_types.h"

namespace dom_storage {

DomStorageHost::DomStorageHost(DomStorageContext* context)
    : context_(context) {
}

DomStorageHost::~DomStorageHost() {
  AreaMap::const_iterator it = connections_.begin();
  for (; it != connections_.end(); ++it)
    it->second.namespace_->CloseStorageArea(it->second.area_.get());
  connections_.clear();  // Clear prior to releasing the context_
}

bool DomStorageHost::OpenStorageArea(int connection_id, int namespace_id,
                                     const GURL& origin) {
  DCHECK(!GetOpenArea(connection_id));
  if (GetOpenArea(connection_id))
    return false;  // Indicates the renderer gave us very bad data.
  NamespaceAndArea references;
  references.namespace_ = context_->GetStorageNamespace(namespace_id);
  if (!references.namespace_.get())
    return false;
  references.area_ = references.namespace_->OpenStorageArea(origin);
  DCHECK(references.area_.get());
  connections_[connection_id] = references;
  return true;
}

void DomStorageHost::CloseStorageArea(int connection_id) {
  AreaMap::iterator found = connections_.find(connection_id);
  if (found == connections_.end())
    return;
  found->second.namespace_->CloseStorageArea(found->second.area_.get());
  connections_.erase(found);
}

bool DomStorageHost::ExtractAreaValues(
    int connection_id, ValuesMap* map) {
  map->clear();
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return false;
  if (!area->IsLoadedInMemory()) {
    DomStorageNamespace* ns = GetNamespace(connection_id);
    DCHECK(ns);
    if (ns->CountInMemoryAreas() > kMaxInMemoryAreas) {
      ns->PurgeMemory(DomStorageNamespace::PURGE_UNOPENED);
      if (ns->CountInMemoryAreas() > kMaxInMemoryAreas)
        ns->PurgeMemory(DomStorageNamespace::PURGE_AGGRESSIVE);
    }
  }
  area->ExtractValues(map);
  return true;
}

unsigned DomStorageHost::GetAreaLength(int connection_id) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return 0;
  return area->Length();
}

base::NullableString16 DomStorageHost::GetAreaKey(int connection_id,
                                                  unsigned index) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return base::NullableString16();
  return area->Key(index);
}

base::NullableString16 DomStorageHost::GetAreaItem(int connection_id,
                                                   const base::string16& key) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return base::NullableString16();
  return area->GetItem(key);
}

bool DomStorageHost::SetAreaItem(
    int connection_id, const base::string16& key,
    const base::string16& value, const GURL& page_url,
    base::NullableString16* old_value) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return false;
  if (!area->SetItem(key, value, old_value))
    return false;
  if (old_value->is_null() || old_value->string() != value)
    context_->NotifyItemSet(area, key, value, *old_value, page_url);
  return true;
}

bool DomStorageHost::RemoveAreaItem(
    int connection_id, const base::string16& key, const GURL& page_url,
    base::string16* old_value) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return false;
  if (!area->RemoveItem(key, old_value))
    return false;
  context_->NotifyItemRemoved(area, key, *old_value, page_url);
  return true;
}

bool DomStorageHost::ClearArea(int connection_id, const GURL& page_url) {
  DomStorageArea* area = GetOpenArea(connection_id);
  if (!area)
    return false;
  if (!area->Clear())
    return false;
  context_->NotifyAreaCleared(area, page_url);
  return true;
}

bool DomStorageHost::HasAreaOpen(
    int namespace_id, const GURL& origin) const {
  AreaMap::const_iterator it = connections_.begin();
  for (; it != connections_.end(); ++it) {
    if (namespace_id == it->second.namespace_->namespace_id() &&
        origin == it->second.area_->origin()) {
      return true;
    }
  }
  return false;
}

DomStorageArea* DomStorageHost::GetOpenArea(int connection_id) {
  AreaMap::iterator found = connections_.find(connection_id);
  if (found == connections_.end())
    return NULL;
  return found->second.area_.get();
}

DomStorageNamespace* DomStorageHost::GetNamespace(int connection_id) {
  AreaMap::iterator found = connections_.find(connection_id);
  if (found == connections_.end())
    return NULL;
  return found->second.namespace_.get();
}

// NamespaceAndArea

DomStorageHost::NamespaceAndArea::NamespaceAndArea() {}
DomStorageHost::NamespaceAndArea::~NamespaceAndArea() {}

}  // namespace dom_storage
<|endoftext|>