<commit_before>// Copyright 2014 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 "content/browser/frame_host/render_widget_host_view_child_frame.h"

#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_factory.h"
#include "cc/surfaces/surface_manager.h"
#include "cc/surfaces/surface_sequence.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/browser_plugin/browser_plugin_guest.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/frame_host/cross_process_frame_connector.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/browser_plugin_guest_mode.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/size_f.h"

namespace content {

RenderWidgetHostViewChildFrame::RenderWidgetHostViewChildFrame(
    RenderWidgetHost* widget_host)
    : host_(RenderWidgetHostImpl::From(widget_host)),
      use_surfaces_(UseSurfacesEnabled()),
      next_surface_sequence_(1u),
      last_output_surface_id_(0),
      current_surface_scale_factor_(1.f),
      ack_pending_count_(0),
      frame_connector_(nullptr),
      weak_factory_(this) {
  if (use_surfaces_) {
    id_allocator_ = CreateSurfaceIdAllocator();
    if (host_->delegate() && host_->delegate()->GetInputEventRouter()) {
      host_->delegate()->GetInputEventRouter()->AddSurfaceIdNamespaceOwner(
          GetSurfaceIdNamespace(), this);
    }
  }

  host_->SetView(this);
}

RenderWidgetHostViewChildFrame::~RenderWidgetHostViewChildFrame() {
  if (!surface_id_.is_null())
    surface_factory_->Destroy(surface_id_);
}

void RenderWidgetHostViewChildFrame::InitAsChild(
    gfx::NativeView parent_view) {
  NOTREACHED();
}

RenderWidgetHost* RenderWidgetHostViewChildFrame::GetRenderWidgetHost() const {
  return host_;
}

void RenderWidgetHostViewChildFrame::SetSize(const gfx::Size& size) {
  host_->WasResized();
}

void RenderWidgetHostViewChildFrame::SetBounds(const gfx::Rect& rect) {
  SetSize(rect.size());
}

void RenderWidgetHostViewChildFrame::Focus() {
}

bool RenderWidgetHostViewChildFrame::HasFocus() const {
  return false;
}

bool RenderWidgetHostViewChildFrame::IsSurfaceAvailableForCopy() const {
  NOTIMPLEMENTED();
  return false;
}

void RenderWidgetHostViewChildFrame::Show() {
  if (!host_->is_hidden())
    return;
  host_->WasShown(ui::LatencyInfo());
}

void RenderWidgetHostViewChildFrame::Hide() {
  if (host_->is_hidden())
    return;
  host_->WasHidden();
}

bool RenderWidgetHostViewChildFrame::IsShowing() {
  return !host_->is_hidden();
}

gfx::Rect RenderWidgetHostViewChildFrame::GetViewBounds() const {
  gfx::Rect rect;
  if (frame_connector_)
    rect = frame_connector_->ChildFrameRect();
  return rect;
}

gfx::Vector2dF RenderWidgetHostViewChildFrame::GetLastScrollOffset() const {
  return last_scroll_offset_;
}

gfx::NativeView RenderWidgetHostViewChildFrame::GetNativeView() const {
  NOTREACHED();
  return NULL;
}

gfx::NativeViewId RenderWidgetHostViewChildFrame::GetNativeViewId() const {
  NOTREACHED();
  return 0;
}

gfx::NativeViewAccessible
RenderWidgetHostViewChildFrame::GetNativeViewAccessible() {
  NOTREACHED();
  return NULL;
}

void RenderWidgetHostViewChildFrame::SetBackgroundColor(SkColor color) {
}

gfx::Size RenderWidgetHostViewChildFrame::GetPhysicalBackingSize() const {
  gfx::Size size;
  if (frame_connector_) {
    size = gfx::ToCeiledSize(
        gfx::ScaleSize(frame_connector_->ChildFrameRect().size(),
                       frame_connector_->device_scale_factor()));
  }
  return size;
}

void RenderWidgetHostViewChildFrame::InitAsPopup(
    RenderWidgetHostView* parent_host_view,
    const gfx::Rect& bounds) {
  NOTREACHED();
}

void RenderWidgetHostViewChildFrame::InitAsFullscreen(
    RenderWidgetHostView* reference_host_view) {
  NOTREACHED();
}

void RenderWidgetHostViewChildFrame::ImeCancelComposition() {
  NOTREACHED();
}

void RenderWidgetHostViewChildFrame::ImeCompositionRangeChanged(
    const gfx::Range& range,
    const std::vector<gfx::Rect>& character_bounds) {
  NOTREACHED();
}

void RenderWidgetHostViewChildFrame::MovePluginWindows(
    const std::vector<WebPluginGeometry>& moves) {
}

void RenderWidgetHostViewChildFrame::UpdateCursor(const WebCursor& cursor) {
}

void RenderWidgetHostViewChildFrame::SetIsLoading(bool is_loading) {
  // It is valid for an inner WebContents's SetIsLoading() to end up here.
  // This is because an inner WebContents's main frame's RenderWidgetHostView
  // is a RenderWidgetHostViewChildFrame. In contrast, when there is no
  // inner/outer WebContents, only subframe's RenderWidgetHostView can be a
  // RenderWidgetHostViewChildFrame which do not get a SetIsLoading() call.
  if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests() &&
      BrowserPluginGuest::IsGuest(
          static_cast<RenderViewHostImpl*>(RenderViewHost::From(host_)))) {
    return;
  }

  NOTREACHED();
}

void RenderWidgetHostViewChildFrame::TextInputStateChanged(
    const ViewHostMsg_TextInputState_Params& params) {
  // TODO(kenrb): Implement.
}

void RenderWidgetHostViewChildFrame::RenderProcessGone(
    base::TerminationStatus status,
    int error_code) {
  if (frame_connector_)
    frame_connector_->RenderProcessGone();
  Destroy();
}

void RenderWidgetHostViewChildFrame::Destroy() {
  if (frame_connector_) {
    frame_connector_->set_view(NULL);
    frame_connector_ = NULL;
  }

  if (use_surfaces_ && host_->delegate() &&
      host_->delegate()->GetInputEventRouter()) {
    host_->delegate()->GetInputEventRouter()->RemoveSurfaceIdNamespaceOwner(
        GetSurfaceIdNamespace());
  }

  host_->SetView(NULL);
  host_ = NULL;
  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}

void RenderWidgetHostViewChildFrame::SetTooltipText(
    const base::string16& tooltip_text) {
}

void RenderWidgetHostViewChildFrame::SelectionChanged(
    const base::string16& text,
    size_t offset,
    const gfx::Range& range) {
}

void RenderWidgetHostViewChildFrame::SelectionBoundsChanged(
    const ViewHostMsg_SelectionBounds_Params& params) {
}

#if defined(OS_ANDROID)
void RenderWidgetHostViewChildFrame::LockCompositingSurface() {
}

void RenderWidgetHostViewChildFrame::UnlockCompositingSurface() {
}
#endif

void RenderWidgetHostViewChildFrame::SurfaceDrawn(uint32 output_surface_id,
                                                  cc::SurfaceDrawStatus drawn) {
  cc::CompositorFrameAck ack;
  DCHECK(ack_pending_count_ > 0);
  if (!surface_returned_resources_.empty())
    ack.resources.swap(surface_returned_resources_);
  if (host_) {
    host_->Send(new ViewMsg_SwapCompositorFrameAck(host_->GetRoutingID(),
                                                   output_surface_id, ack));
  }
  ack_pending_count_--;
}

void RenderWidgetHostViewChildFrame::OnSwapCompositorFrame(
      uint32 output_surface_id,
      scoped_ptr<cc::CompositorFrame> frame) {
  last_scroll_offset_ = frame->metadata.root_scroll_offset;

  if (!frame_connector_)
    return;

  // When not using surfaces, the frame just gets proxied to
  // the embedder's renderer to be composited.
  if (!frame->delegated_frame_data || !use_surfaces_) {
    frame_connector_->ChildFrameCompositorFrameSwapped(
        output_surface_id,
        host_->GetProcess()->GetID(),
        host_->GetRoutingID(),
        frame.Pass());
    return;
  }

  cc::RenderPass* root_pass =
      frame->delegated_frame_data->render_pass_list.back();

  gfx::Size frame_size = root_pass->output_rect.size();
  float scale_factor = frame->metadata.device_scale_factor;

  // Check whether we need to recreate the cc::Surface, which means the child
  // frame renderer has changed its output surface, or size, or scale factor.
  if (output_surface_id != last_output_surface_id_ && surface_factory_) {
    surface_factory_->Destroy(surface_id_);
    surface_factory_.reset();
  }
  if (output_surface_id != last_output_surface_id_ ||
      frame_size != current_surface_size_ ||
      scale_factor != current_surface_scale_factor_) {
    ClearCompositorSurfaceIfNecessary();
    last_output_surface_id_ = output_surface_id;
    current_surface_size_ = frame_size;
    current_surface_scale_factor_ = scale_factor;
  }

  if (!surface_factory_) {
    cc::SurfaceManager* manager = GetSurfaceManager();
    surface_factory_ = make_scoped_ptr(new cc::SurfaceFactory(manager, this));
  }

  if (surface_id_.is_null()) {
    surface_id_ = id_allocator_->GenerateId();
    surface_factory_->Create(surface_id_);

    cc::SurfaceSequence sequence = cc::SurfaceSequence(
        id_allocator_->id_namespace(), next_surface_sequence_++);
    // The renderer process will satisfy this dependency when it creates a
    // SurfaceLayer.
    cc::SurfaceManager* manager = GetSurfaceManager();
    manager->GetSurfaceForId(surface_id_)->AddDestructionDependency(sequence);
    frame_connector_->SetChildFrameSurface(surface_id_, frame_size,
                                           scale_factor, sequence);
  }

  cc::SurfaceFactory::DrawCallback ack_callback =
      base::Bind(&RenderWidgetHostViewChildFrame::SurfaceDrawn, AsWeakPtr(),
                 output_surface_id);
  ack_pending_count_++;
  // If this value grows very large, something is going wrong.
  DCHECK(ack_pending_count_ < 1000);
  surface_factory_->SubmitCompositorFrame(surface_id_, frame.Pass(),
                                          ack_callback);
}

void RenderWidgetHostViewChildFrame::GetScreenInfo(
    blink::WebScreenInfo* results) {
  if (!frame_connector_)
    return;
  frame_connector_->GetScreenInfo(results);
}

bool RenderWidgetHostViewChildFrame::GetScreenColorProfile(
    std::vector<char>* color_profile) {
  if (!frame_connector_)
    return false;
  DCHECK(color_profile->empty());
  NOTIMPLEMENTED(); // TODO(port): Implement.
  return false;
}

gfx::Rect RenderWidgetHostViewChildFrame::GetBoundsInRootWindow() {
  // We do not have any root window specific parts in this view.
  return GetViewBounds();
}

#if defined(USE_AURA)
void RenderWidgetHostViewChildFrame::ProcessAckedTouchEvent(
    const TouchEventWithLatencyInfo& touch,
    InputEventAckState ack_result) {
}
#endif  // defined(USE_AURA)

bool RenderWidgetHostViewChildFrame::LockMouse() {
  return false;
}

void RenderWidgetHostViewChildFrame::UnlockMouse() {
}

uint32_t RenderWidgetHostViewChildFrame::GetSurfaceIdNamespace() {
  if (!use_surfaces_)
    return 0;

  return id_allocator_->id_namespace();
}

void RenderWidgetHostViewChildFrame::ProcessKeyboardEvent(
    const NativeWebKeyboardEvent& event) {
  host_->ForwardKeyboardEvent(event);
}

void RenderWidgetHostViewChildFrame::ProcessMouseEvent(
    const blink::WebMouseEvent& event) {
  host_->ForwardMouseEvent(event);
}

void RenderWidgetHostViewChildFrame::ProcessMouseWheelEvent(
    const blink::WebMouseWheelEvent& event) {
  if (event.deltaX != 0 || event.deltaY != 0)
    host_->ForwardWheelEvent(event);
}

#if defined(OS_MACOSX)
void RenderWidgetHostViewChildFrame::SetActive(bool active) {
}

void RenderWidgetHostViewChildFrame::SetWindowVisibility(bool visible) {
}

void RenderWidgetHostViewChildFrame::WindowFrameChanged() {
}

void RenderWidgetHostViewChildFrame::ShowDefinitionForSelection() {
}

bool RenderWidgetHostViewChildFrame::SupportsSpeech() const {
  return false;
}

void RenderWidgetHostViewChildFrame::SpeakSelection() {
}

bool RenderWidgetHostViewChildFrame::IsSpeaking() const {
  return false;
}

void RenderWidgetHostViewChildFrame::StopSpeaking() {
}

bool RenderWidgetHostViewChildFrame::PostProcessEventForPluginIme(
      const NativeWebKeyboardEvent& event) {
  return false;
}
#endif // defined(OS_MACOSX)

void RenderWidgetHostViewChildFrame::CopyFromCompositingSurface(
    const gfx::Rect& src_subrect,
    const gfx::Size& /* dst_size */,
    ReadbackRequestCallback& callback,
    const SkColorType preferred_color_type) {
  callback.Run(SkBitmap(), READBACK_FAILED);
}

void RenderWidgetHostViewChildFrame::CopyFromCompositingSurfaceToVideoFrame(
      const gfx::Rect& src_subrect,
      const scoped_refptr<media::VideoFrame>& target,
      const base::Callback<void(bool)>& callback) {
  NOTIMPLEMENTED();
  callback.Run(false);
}

bool RenderWidgetHostViewChildFrame::CanCopyToVideoFrame() const {
  return false;
}

bool RenderWidgetHostViewChildFrame::HasAcceleratedSurface(
      const gfx::Size& desired_size) {
  return false;
}

gfx::GLSurfaceHandle RenderWidgetHostViewChildFrame::GetCompositingSurface() {
  return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NULL_TRANSPORT);
}

#if defined(OS_WIN)
void RenderWidgetHostViewChildFrame::SetParentNativeViewAccessible(
    gfx::NativeViewAccessible accessible_parent) {
}

gfx::NativeViewId RenderWidgetHostViewChildFrame::GetParentForWindowlessPlugin()
    const {
  return NULL;
}
#endif // defined(OS_WIN)

// cc::SurfaceFactoryClient implementation.
void RenderWidgetHostViewChildFrame::ReturnResources(
    const cc::ReturnedResourceArray& resources) {
  if (resources.empty())
    return;

  if (!ack_pending_count_ && host_) {
    cc::CompositorFrameAck ack;
    std::copy(resources.begin(), resources.end(),
              std::back_inserter(ack.resources));
    host_->Send(new ViewMsg_ReclaimCompositorResources(
        host_->GetRoutingID(), last_output_surface_id_, ack));
    return;
  }

  std::copy(resources.begin(), resources.end(),
            std::back_inserter(surface_returned_resources_));
}

BrowserAccessibilityManager*
RenderWidgetHostViewChildFrame::CreateBrowserAccessibilityManager(
    BrowserAccessibilityDelegate* delegate) {
  return BrowserAccessibilityManager::Create(
      BrowserAccessibilityManager::GetEmptyDocument(), delegate);
}

void RenderWidgetHostViewChildFrame::ClearCompositorSurfaceIfNecessary() {
  if (surface_factory_ && !surface_id_.is_null())
    surface_factory_->Destroy(surface_id_);
  surface_id_ = cc::SurfaceId();
}

}  // namespace content
<commit_msg>Remove couple of Ime related NOTREACHED() in RWHVChildFrame.   These make --site-per-process signin page unusable in debug builds.<commit_after>// Copyright 2014 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 "content/browser/frame_host/render_widget_host_view_child_frame.h"

#include "cc/surfaces/surface.h"
#include "cc/surfaces/surface_factory.h"
#include "cc/surfaces/surface_manager.h"
#include "cc/surfaces/surface_sequence.h"
#include "content/browser/accessibility/browser_accessibility_manager.h"
#include "content/browser/browser_plugin/browser_plugin_guest.h"
#include "content/browser/compositor/surface_utils.h"
#include "content/browser/frame_host/cross_process_frame_connector.h"
#include "content/browser/gpu/compositor_util.h"
#include "content/browser/renderer_host/render_view_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_delegate.h"
#include "content/browser/renderer_host/render_widget_host_impl.h"
#include "content/browser/renderer_host/render_widget_host_input_event_router.h"
#include "content/common/gpu/gpu_messages.h"
#include "content/common/view_messages.h"
#include "content/public/browser/render_process_host.h"
#include "content/public/common/browser_plugin_guest_mode.h"
#include "ui/gfx/geometry/size_conversions.h"
#include "ui/gfx/geometry/size_f.h"

namespace content {

RenderWidgetHostViewChildFrame::RenderWidgetHostViewChildFrame(
    RenderWidgetHost* widget_host)
    : host_(RenderWidgetHostImpl::From(widget_host)),
      use_surfaces_(UseSurfacesEnabled()),
      next_surface_sequence_(1u),
      last_output_surface_id_(0),
      current_surface_scale_factor_(1.f),
      ack_pending_count_(0),
      frame_connector_(nullptr),
      weak_factory_(this) {
  if (use_surfaces_) {
    id_allocator_ = CreateSurfaceIdAllocator();
    if (host_->delegate() && host_->delegate()->GetInputEventRouter()) {
      host_->delegate()->GetInputEventRouter()->AddSurfaceIdNamespaceOwner(
          GetSurfaceIdNamespace(), this);
    }
  }

  host_->SetView(this);
}

RenderWidgetHostViewChildFrame::~RenderWidgetHostViewChildFrame() {
  if (!surface_id_.is_null())
    surface_factory_->Destroy(surface_id_);
}

void RenderWidgetHostViewChildFrame::InitAsChild(
    gfx::NativeView parent_view) {
  NOTREACHED();
}

RenderWidgetHost* RenderWidgetHostViewChildFrame::GetRenderWidgetHost() const {
  return host_;
}

void RenderWidgetHostViewChildFrame::SetSize(const gfx::Size& size) {
  host_->WasResized();
}

void RenderWidgetHostViewChildFrame::SetBounds(const gfx::Rect& rect) {
  SetSize(rect.size());
}

void RenderWidgetHostViewChildFrame::Focus() {
}

bool RenderWidgetHostViewChildFrame::HasFocus() const {
  return false;
}

bool RenderWidgetHostViewChildFrame::IsSurfaceAvailableForCopy() const {
  NOTIMPLEMENTED();
  return false;
}

void RenderWidgetHostViewChildFrame::Show() {
  if (!host_->is_hidden())
    return;
  host_->WasShown(ui::LatencyInfo());
}

void RenderWidgetHostViewChildFrame::Hide() {
  if (host_->is_hidden())
    return;
  host_->WasHidden();
}

bool RenderWidgetHostViewChildFrame::IsShowing() {
  return !host_->is_hidden();
}

gfx::Rect RenderWidgetHostViewChildFrame::GetViewBounds() const {
  gfx::Rect rect;
  if (frame_connector_)
    rect = frame_connector_->ChildFrameRect();
  return rect;
}

gfx::Vector2dF RenderWidgetHostViewChildFrame::GetLastScrollOffset() const {
  return last_scroll_offset_;
}

gfx::NativeView RenderWidgetHostViewChildFrame::GetNativeView() const {
  NOTREACHED();
  return NULL;
}

gfx::NativeViewId RenderWidgetHostViewChildFrame::GetNativeViewId() const {
  NOTREACHED();
  return 0;
}

gfx::NativeViewAccessible
RenderWidgetHostViewChildFrame::GetNativeViewAccessible() {
  NOTREACHED();
  return NULL;
}

void RenderWidgetHostViewChildFrame::SetBackgroundColor(SkColor color) {
}

gfx::Size RenderWidgetHostViewChildFrame::GetPhysicalBackingSize() const {
  gfx::Size size;
  if (frame_connector_) {
    size = gfx::ToCeiledSize(
        gfx::ScaleSize(frame_connector_->ChildFrameRect().size(),
                       frame_connector_->device_scale_factor()));
  }
  return size;
}

void RenderWidgetHostViewChildFrame::InitAsPopup(
    RenderWidgetHostView* parent_host_view,
    const gfx::Rect& bounds) {
  NOTREACHED();
}

void RenderWidgetHostViewChildFrame::InitAsFullscreen(
    RenderWidgetHostView* reference_host_view) {
  NOTREACHED();
}

void RenderWidgetHostViewChildFrame::ImeCancelComposition() {
  // TODO(kenrb): Fix OOPIF Ime.
}

void RenderWidgetHostViewChildFrame::ImeCompositionRangeChanged(
    const gfx::Range& range,
    const std::vector<gfx::Rect>& character_bounds) {
  // TODO(kenrb): Fix OOPIF Ime.
}

void RenderWidgetHostViewChildFrame::MovePluginWindows(
    const std::vector<WebPluginGeometry>& moves) {
}

void RenderWidgetHostViewChildFrame::UpdateCursor(const WebCursor& cursor) {
}

void RenderWidgetHostViewChildFrame::SetIsLoading(bool is_loading) {
  // It is valid for an inner WebContents's SetIsLoading() to end up here.
  // This is because an inner WebContents's main frame's RenderWidgetHostView
  // is a RenderWidgetHostViewChildFrame. In contrast, when there is no
  // inner/outer WebContents, only subframe's RenderWidgetHostView can be a
  // RenderWidgetHostViewChildFrame which do not get a SetIsLoading() call.
  if (BrowserPluginGuestMode::UseCrossProcessFramesForGuests() &&
      BrowserPluginGuest::IsGuest(
          static_cast<RenderViewHostImpl*>(RenderViewHost::From(host_)))) {
    return;
  }

  NOTREACHED();
}

void RenderWidgetHostViewChildFrame::TextInputStateChanged(
    const ViewHostMsg_TextInputState_Params& params) {
  // TODO(kenrb): Implement.
}

void RenderWidgetHostViewChildFrame::RenderProcessGone(
    base::TerminationStatus status,
    int error_code) {
  if (frame_connector_)
    frame_connector_->RenderProcessGone();
  Destroy();
}

void RenderWidgetHostViewChildFrame::Destroy() {
  if (frame_connector_) {
    frame_connector_->set_view(NULL);
    frame_connector_ = NULL;
  }

  if (use_surfaces_ && host_->delegate() &&
      host_->delegate()->GetInputEventRouter()) {
    host_->delegate()->GetInputEventRouter()->RemoveSurfaceIdNamespaceOwner(
        GetSurfaceIdNamespace());
  }

  host_->SetView(NULL);
  host_ = NULL;
  base::MessageLoop::current()->DeleteSoon(FROM_HERE, this);
}

void RenderWidgetHostViewChildFrame::SetTooltipText(
    const base::string16& tooltip_text) {
}

void RenderWidgetHostViewChildFrame::SelectionChanged(
    const base::string16& text,
    size_t offset,
    const gfx::Range& range) {
}

void RenderWidgetHostViewChildFrame::SelectionBoundsChanged(
    const ViewHostMsg_SelectionBounds_Params& params) {
}

#if defined(OS_ANDROID)
void RenderWidgetHostViewChildFrame::LockCompositingSurface() {
}

void RenderWidgetHostViewChildFrame::UnlockCompositingSurface() {
}
#endif

void RenderWidgetHostViewChildFrame::SurfaceDrawn(uint32 output_surface_id,
                                                  cc::SurfaceDrawStatus drawn) {
  cc::CompositorFrameAck ack;
  DCHECK(ack_pending_count_ > 0);
  if (!surface_returned_resources_.empty())
    ack.resources.swap(surface_returned_resources_);
  if (host_) {
    host_->Send(new ViewMsg_SwapCompositorFrameAck(host_->GetRoutingID(),
                                                   output_surface_id, ack));
  }
  ack_pending_count_--;
}

void RenderWidgetHostViewChildFrame::OnSwapCompositorFrame(
      uint32 output_surface_id,
      scoped_ptr<cc::CompositorFrame> frame) {
  last_scroll_offset_ = frame->metadata.root_scroll_offset;

  if (!frame_connector_)
    return;

  // When not using surfaces, the frame just gets proxied to
  // the embedder's renderer to be composited.
  if (!frame->delegated_frame_data || !use_surfaces_) {
    frame_connector_->ChildFrameCompositorFrameSwapped(
        output_surface_id,
        host_->GetProcess()->GetID(),
        host_->GetRoutingID(),
        frame.Pass());
    return;
  }

  cc::RenderPass* root_pass =
      frame->delegated_frame_data->render_pass_list.back();

  gfx::Size frame_size = root_pass->output_rect.size();
  float scale_factor = frame->metadata.device_scale_factor;

  // Check whether we need to recreate the cc::Surface, which means the child
  // frame renderer has changed its output surface, or size, or scale factor.
  if (output_surface_id != last_output_surface_id_ && surface_factory_) {
    surface_factory_->Destroy(surface_id_);
    surface_factory_.reset();
  }
  if (output_surface_id != last_output_surface_id_ ||
      frame_size != current_surface_size_ ||
      scale_factor != current_surface_scale_factor_) {
    ClearCompositorSurfaceIfNecessary();
    last_output_surface_id_ = output_surface_id;
    current_surface_size_ = frame_size;
    current_surface_scale_factor_ = scale_factor;
  }

  if (!surface_factory_) {
    cc::SurfaceManager* manager = GetSurfaceManager();
    surface_factory_ = make_scoped_ptr(new cc::SurfaceFactory(manager, this));
  }

  if (surface_id_.is_null()) {
    surface_id_ = id_allocator_->GenerateId();
    surface_factory_->Create(surface_id_);

    cc::SurfaceSequence sequence = cc::SurfaceSequence(
        id_allocator_->id_namespace(), next_surface_sequence_++);
    // The renderer process will satisfy this dependency when it creates a
    // SurfaceLayer.
    cc::SurfaceManager* manager = GetSurfaceManager();
    manager->GetSurfaceForId(surface_id_)->AddDestructionDependency(sequence);
    frame_connector_->SetChildFrameSurface(surface_id_, frame_size,
                                           scale_factor, sequence);
  }

  cc::SurfaceFactory::DrawCallback ack_callback =
      base::Bind(&RenderWidgetHostViewChildFrame::SurfaceDrawn, AsWeakPtr(),
                 output_surface_id);
  ack_pending_count_++;
  // If this value grows very large, something is going wrong.
  DCHECK(ack_pending_count_ < 1000);
  surface_factory_->SubmitCompositorFrame(surface_id_, frame.Pass(),
                                          ack_callback);
}

void RenderWidgetHostViewChildFrame::GetScreenInfo(
    blink::WebScreenInfo* results) {
  if (!frame_connector_)
    return;
  frame_connector_->GetScreenInfo(results);
}

bool RenderWidgetHostViewChildFrame::GetScreenColorProfile(
    std::vector<char>* color_profile) {
  if (!frame_connector_)
    return false;
  DCHECK(color_profile->empty());
  NOTIMPLEMENTED(); // TODO(port): Implement.
  return false;
}

gfx::Rect RenderWidgetHostViewChildFrame::GetBoundsInRootWindow() {
  // We do not have any root window specific parts in this view.
  return GetViewBounds();
}

#if defined(USE_AURA)
void RenderWidgetHostViewChildFrame::ProcessAckedTouchEvent(
    const TouchEventWithLatencyInfo& touch,
    InputEventAckState ack_result) {
}
#endif  // defined(USE_AURA)

bool RenderWidgetHostViewChildFrame::LockMouse() {
  return false;
}

void RenderWidgetHostViewChildFrame::UnlockMouse() {
}

uint32_t RenderWidgetHostViewChildFrame::GetSurfaceIdNamespace() {
  if (!use_surfaces_)
    return 0;

  return id_allocator_->id_namespace();
}

void RenderWidgetHostViewChildFrame::ProcessKeyboardEvent(
    const NativeWebKeyboardEvent& event) {
  host_->ForwardKeyboardEvent(event);
}

void RenderWidgetHostViewChildFrame::ProcessMouseEvent(
    const blink::WebMouseEvent& event) {
  host_->ForwardMouseEvent(event);
}

void RenderWidgetHostViewChildFrame::ProcessMouseWheelEvent(
    const blink::WebMouseWheelEvent& event) {
  if (event.deltaX != 0 || event.deltaY != 0)
    host_->ForwardWheelEvent(event);
}

#if defined(OS_MACOSX)
void RenderWidgetHostViewChildFrame::SetActive(bool active) {
}

void RenderWidgetHostViewChildFrame::SetWindowVisibility(bool visible) {
}

void RenderWidgetHostViewChildFrame::WindowFrameChanged() {
}

void RenderWidgetHostViewChildFrame::ShowDefinitionForSelection() {
}

bool RenderWidgetHostViewChildFrame::SupportsSpeech() const {
  return false;
}

void RenderWidgetHostViewChildFrame::SpeakSelection() {
}

bool RenderWidgetHostViewChildFrame::IsSpeaking() const {
  return false;
}

void RenderWidgetHostViewChildFrame::StopSpeaking() {
}

bool RenderWidgetHostViewChildFrame::PostProcessEventForPluginIme(
      const NativeWebKeyboardEvent& event) {
  return false;
}
#endif // defined(OS_MACOSX)

void RenderWidgetHostViewChildFrame::CopyFromCompositingSurface(
    const gfx::Rect& src_subrect,
    const gfx::Size& /* dst_size */,
    ReadbackRequestCallback& callback,
    const SkColorType preferred_color_type) {
  callback.Run(SkBitmap(), READBACK_FAILED);
}

void RenderWidgetHostViewChildFrame::CopyFromCompositingSurfaceToVideoFrame(
      const gfx::Rect& src_subrect,
      const scoped_refptr<media::VideoFrame>& target,
      const base::Callback<void(bool)>& callback) {
  NOTIMPLEMENTED();
  callback.Run(false);
}

bool RenderWidgetHostViewChildFrame::CanCopyToVideoFrame() const {
  return false;
}

bool RenderWidgetHostViewChildFrame::HasAcceleratedSurface(
      const gfx::Size& desired_size) {
  return false;
}

gfx::GLSurfaceHandle RenderWidgetHostViewChildFrame::GetCompositingSurface() {
  return gfx::GLSurfaceHandle(gfx::kNullPluginWindow, gfx::NULL_TRANSPORT);
}

#if defined(OS_WIN)
void RenderWidgetHostViewChildFrame::SetParentNativeViewAccessible(
    gfx::NativeViewAccessible accessible_parent) {
}

gfx::NativeViewId RenderWidgetHostViewChildFrame::GetParentForWindowlessPlugin()
    const {
  return NULL;
}
#endif // defined(OS_WIN)

// cc::SurfaceFactoryClient implementation.
void RenderWidgetHostViewChildFrame::ReturnResources(
    const cc::ReturnedResourceArray& resources) {
  if (resources.empty())
    return;

  if (!ack_pending_count_ && host_) {
    cc::CompositorFrameAck ack;
    std::copy(resources.begin(), resources.end(),
              std::back_inserter(ack.resources));
    host_->Send(new ViewMsg_ReclaimCompositorResources(
        host_->GetRoutingID(), last_output_surface_id_, ack));
    return;
  }

  std::copy(resources.begin(), resources.end(),
            std::back_inserter(surface_returned_resources_));
}

BrowserAccessibilityManager*
RenderWidgetHostViewChildFrame::CreateBrowserAccessibilityManager(
    BrowserAccessibilityDelegate* delegate) {
  return BrowserAccessibilityManager::Create(
      BrowserAccessibilityManager::GetEmptyDocument(), delegate);
}

void RenderWidgetHostViewChildFrame::ClearCompositorSurfaceIfNecessary() {
  if (surface_factory_ && !surface_id_.is_null())
    surface_factory_->Destroy(surface_id_);
  surface_id_ = cc::SurfaceId();
}

}  // namespace content
<|endoftext|>


<commit_before>// Copyright (c) 2013 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 "content/browser/renderer_host/smooth_scroll_gesture_controller.h"

#include "base/debug/trace_event.h"
#include "base/message_loop.h"
#include "content/common/view_messages.h"
#include "content/port/browser/render_widget_host_view_port.h"
#include "content/port/browser/smooth_scroll_gesture.h"
#include "content/public/browser/render_widget_host.h"

namespace content {

namespace {

// How many milliseconds apart synthetic scroll messages should be sent.
const int kSyntheticScrollMessageIntervalMs = 8;

}  // namespace

SmoothScrollGestureController::SmoothScrollGestureController()
    : rwh_(NULL) {
}

SmoothScrollGestureController::~SmoothScrollGestureController() {
}

void SmoothScrollGestureController::BeginSmoothScroll(
    RenderWidgetHostViewPort* view,
    const ViewHostMsg_BeginSmoothScroll_Params& params) {
  if (pending_smooth_scroll_gesture_.get())
    return;

  rwh_ = view->GetRenderWidgetHost();
  pending_smooth_scroll_gesture_ = view->CreateSmoothScrollGesture(
      params.scroll_down,
      params.pixels_to_scroll,
      params.mouse_event_x,
      params.mouse_event_y);

  timer_.Start(FROM_HERE, GetSyntheticScrollMessageInterval(), this,
               &SmoothScrollGestureController::OnTimer);
}

base::TimeDelta
    SmoothScrollGestureController::GetSyntheticScrollMessageInterval() const {
  return base::TimeDelta::FromMilliseconds(kSyntheticScrollMessageIntervalMs);
}

void SmoothScrollGestureController::OnTimer() {
  base::TimeTicks now = base::TimeTicks::Now();
  if (!pending_smooth_scroll_gesture_->ForwardInputEvents(now, rwh_)) {
    timer_.Stop();
    pending_smooth_scroll_gesture_ = NULL;
    rwh_->Send(new ViewMsg_SmoothScrollCompleted(rwh_->GetRoutingID()));
  }
}

}  // namespace content
<commit_msg>Send synthetic scroll messages every 7 ms.<commit_after>// Copyright (c) 2013 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 "content/browser/renderer_host/smooth_scroll_gesture_controller.h"

#include "base/debug/trace_event.h"
#include "base/message_loop.h"
#include "content/common/view_messages.h"
#include "content/port/browser/render_widget_host_view_port.h"
#include "content/port/browser/smooth_scroll_gesture.h"
#include "content/public/browser/render_widget_host.h"

namespace content {

namespace {

// How many milliseconds apart synthetic scroll messages should be sent.
const int kSyntheticScrollMessageIntervalMs = 7;

}  // namespace

SmoothScrollGestureController::SmoothScrollGestureController()
    : rwh_(NULL) {
}

SmoothScrollGestureController::~SmoothScrollGestureController() {
}

void SmoothScrollGestureController::BeginSmoothScroll(
    RenderWidgetHostViewPort* view,
    const ViewHostMsg_BeginSmoothScroll_Params& params) {
  if (pending_smooth_scroll_gesture_.get())
    return;

  rwh_ = view->GetRenderWidgetHost();
  pending_smooth_scroll_gesture_ = view->CreateSmoothScrollGesture(
      params.scroll_down,
      params.pixels_to_scroll,
      params.mouse_event_x,
      params.mouse_event_y);

  timer_.Start(FROM_HERE, GetSyntheticScrollMessageInterval(), this,
               &SmoothScrollGestureController::OnTimer);
}

base::TimeDelta
    SmoothScrollGestureController::GetSyntheticScrollMessageInterval() const {
  return base::TimeDelta::FromMilliseconds(kSyntheticScrollMessageIntervalMs);
}

void SmoothScrollGestureController::OnTimer() {
  base::TimeTicks now = base::TimeTicks::Now();
  if (!pending_smooth_scroll_gesture_->ForwardInputEvents(now, rwh_)) {
    timer_.Stop();
    pending_smooth_scroll_gesture_ = NULL;
    rwh_->Send(new ViewMsg_SmoothScrollCompleted(rwh_->GetRoutingID()));
  }
}

}  // namespace content
<|endoftext|>


<commit_before>// Copyright (c) 2011 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 "remoting/host/desktop_environment.h"

#include "base/bind.h"
#include "base/compiler_specific.h"
#include "remoting/host/capturer.h"
#include "remoting/host/chromoting_host.h"
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/continue_window.h"
#include "remoting/host/curtain.h"
#include "remoting/host/disconnect_window.h"
#include "remoting/host/event_executor.h"
#include "remoting/host/local_input_monitor.h"

static const int kContinueWindowTimeoutMs = 10 * 60 * 1000;

namespace remoting {

// UIThreadProxy proxies DesktopEnvironment method calls to the UI
// thread. This is neccessary so that DesktopEnvironment can be
// deleted synchronously even while there are pending tasks on the
// message queue.
class UIThreadProxy : public base::RefCountedThreadSafe<UIThreadProxy> {
 public:
  UIThreadProxy(ChromotingHostContext* context)
      : context_(context) {
  }

  void Detach() {
    DCHECK(context_->IsUIThread());
    context_ = NULL;
  }

  void CallOnUIThread(const tracked_objects::Location& from_here,
                      const base::Closure& closure) {
    if (context_) {
      context_->PostTaskToUIThread(from_here, base::Bind(
          &UIThreadProxy::CallClosure, this, closure));
    }
  }

  void CallOnUIThreadDelayed(const tracked_objects::Location& from_here,
                             const base::Closure& closure,
                             int delay_ms) {
    if (context_) {
      context_->PostDelayedTaskToUIThread(from_here, base::Bind(
          &UIThreadProxy::CallClosure, this, closure), delay_ms);
    }
  }

 private:
  friend class base::RefCountedThreadSafe<UIThreadProxy>;

  virtual ~UIThreadProxy() { }

  void CallClosure(const base::Closure& closure) {
    if (context_)
      closure.Run();
  }

  ChromotingHostContext* context_;

  DISALLOW_COPY_AND_ASSIGN(UIThreadProxy);
};

// static
DesktopEnvironment* DesktopEnvironment::Create(ChromotingHostContext* context) {
  Capturer* capturer = Capturer::Create();
  EventExecutor* event_executor =
      EventExecutor::Create(context->desktop_message_loop(), capturer);
  Curtain* curtain = Curtain::Create();
  DisconnectWindow* disconnect_window = DisconnectWindow::Create();
  ContinueWindow* continue_window = ContinueWindow::Create();
  LocalInputMonitor* local_input_monitor = LocalInputMonitor::Create();

  return new DesktopEnvironment(context, capturer, event_executor, curtain,
                                disconnect_window, continue_window,
                                local_input_monitor);
}

DesktopEnvironment::DesktopEnvironment(ChromotingHostContext* context,
                                       Capturer* capturer,
                                       EventExecutor* event_executor,
                                       Curtain* curtain,
                                       DisconnectWindow* disconnect_window,
                                       ContinueWindow* continue_window,
                                       LocalInputMonitor* local_input_monitor)
    : host_(NULL),
      context_(context),
      capturer_(capturer),
      event_executor_(event_executor),
      curtain_(curtain),
      disconnect_window_(disconnect_window),
      continue_window_(continue_window),
      local_input_monitor_(local_input_monitor),
      is_monitoring_local_inputs_(false),
      continue_timer_started_(false),
      proxy_(new UIThreadProxy(context)) {
}

DesktopEnvironment::~DesktopEnvironment() {
}

void DesktopEnvironment::Shutdown() {
  DCHECK(context_->IsUIThread());

  MonitorLocalInputs(false);
  ShowDisconnectWindow(false, std::string());
  ShowContinueWindow(false);
  StartContinueWindowTimer(false);

  proxy_->Detach();
}

void DesktopEnvironment::OnConnect(const std::string& username) {
  proxy_->CallOnUIThread(FROM_HERE, base::Bind(
      &DesktopEnvironment::ProcessOnConnect, base::Unretained(this), username));
}

void DesktopEnvironment::OnLastDisconnect() {
  proxy_->CallOnUIThread(FROM_HERE, base::Bind(
      &DesktopEnvironment::ProcessOnLastDisconnect, base::Unretained(this)));
}

void DesktopEnvironment::OnPause(bool pause) {
  proxy_->CallOnUIThread(FROM_HERE, base::Bind(
      &DesktopEnvironment::ProcessOnPause, base::Unretained(this), pause));
}

void DesktopEnvironment::ProcessOnConnect(const std::string& username) {
  DCHECK(context_->IsUIThread());

  MonitorLocalInputs(true);
  ShowDisconnectWindow(true, username);
  StartContinueWindowTimer(true);
}

void DesktopEnvironment::ProcessOnLastDisconnect() {
  DCHECK(context_->IsUIThread());

  MonitorLocalInputs(false);
  ShowDisconnectWindow(false, std::string());
  ShowContinueWindow(false);
  StartContinueWindowTimer(false);
}

void DesktopEnvironment::ProcessOnPause(bool pause) {
  StartContinueWindowTimer(!pause);
}

void DesktopEnvironment::MonitorLocalInputs(bool enable) {
  DCHECK(context_->IsUIThread());

  if (enable == is_monitoring_local_inputs_)
    return;
  if (enable) {
    local_input_monitor_->Start(host_);
  } else {
    local_input_monitor_->Stop();
  }
  is_monitoring_local_inputs_ = enable;
}

void DesktopEnvironment::ShowDisconnectWindow(bool show,
                                              const std::string& username) {
  DCHECK(context_->IsUIThread());

  if (show) {
    disconnect_window_->Show(host_, username);
  } else {
    disconnect_window_->Hide();
  }
}

void DesktopEnvironment::ShowContinueWindow(bool show) {
  DCHECK(context_->IsUIThread());

  if (show) {
    continue_window_->Show(host_);
  } else {
    continue_window_->Hide();
  }
}

void DesktopEnvironment::StartContinueWindowTimer(bool start) {
  DCHECK(context_->IsUIThread());

  if (start && ! continue_timer_started_) {
    continue_timer_target_time_ = base::Time::Now() +
        base::TimeDelta::FromMilliseconds(kContinueWindowTimeoutMs);
    proxy_->CallOnUIThreadDelayed(
        FROM_HERE, base::Bind(&DesktopEnvironment::ContinueWindowTimerFunc,
                              base::Unretained(this)),
        kContinueWindowTimeoutMs);
  }

  continue_timer_started_ = start;
}

void DesktopEnvironment::ContinueWindowTimerFunc() {
  DCHECK(context_->IsUIThread());

  // This function may be called prematurely if timer was stopped and
  // then started again. In that case we just ignore this call.
  if (continue_timer_target_time_ > base::Time::Now())
    return;

  host_->PauseSession(true);
  ShowContinueWindow(true);
}

}  // namespace remoting
<commit_msg>Fix up confirmation window not reshowing.<commit_after>// Copyright (c) 2011 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 "remoting/host/desktop_environment.h"

#include "base/bind.h"
#include "base/compiler_specific.h"
#include "remoting/host/capturer.h"
#include "remoting/host/chromoting_host.h"
#include "remoting/host/chromoting_host_context.h"
#include "remoting/host/continue_window.h"
#include "remoting/host/curtain.h"
#include "remoting/host/disconnect_window.h"
#include "remoting/host/event_executor.h"
#include "remoting/host/local_input_monitor.h"

static const int kContinueWindowTimeoutMs = 10 * 60 * 1000;

namespace remoting {

// UIThreadProxy proxies DesktopEnvironment method calls to the UI
// thread. This is neccessary so that DesktopEnvironment can be
// deleted synchronously even while there are pending tasks on the
// message queue.
class UIThreadProxy : public base::RefCountedThreadSafe<UIThreadProxy> {
 public:
  UIThreadProxy(ChromotingHostContext* context)
      : context_(context) {
  }

  void Detach() {
    DCHECK(context_->IsUIThread());
    context_ = NULL;
  }

  void CallOnUIThread(const tracked_objects::Location& from_here,
                      const base::Closure& closure) {
    if (context_) {
      context_->PostTaskToUIThread(from_here, base::Bind(
          &UIThreadProxy::CallClosure, this, closure));
    }
  }

  void CallOnUIThreadDelayed(const tracked_objects::Location& from_here,
                             const base::Closure& closure,
                             int delay_ms) {
    if (context_) {
      context_->PostDelayedTaskToUIThread(from_here, base::Bind(
          &UIThreadProxy::CallClosure, this, closure), delay_ms);
    }
  }

 private:
  friend class base::RefCountedThreadSafe<UIThreadProxy>;

  virtual ~UIThreadProxy() { }

  void CallClosure(const base::Closure& closure) {
    if (context_)
      closure.Run();
  }

  ChromotingHostContext* context_;

  DISALLOW_COPY_AND_ASSIGN(UIThreadProxy);
};

// static
DesktopEnvironment* DesktopEnvironment::Create(ChromotingHostContext* context) {
  Capturer* capturer = Capturer::Create();
  EventExecutor* event_executor =
      EventExecutor::Create(context->desktop_message_loop(), capturer);
  Curtain* curtain = Curtain::Create();
  DisconnectWindow* disconnect_window = DisconnectWindow::Create();
  ContinueWindow* continue_window = ContinueWindow::Create();
  LocalInputMonitor* local_input_monitor = LocalInputMonitor::Create();

  return new DesktopEnvironment(context, capturer, event_executor, curtain,
                                disconnect_window, continue_window,
                                local_input_monitor);
}

DesktopEnvironment::DesktopEnvironment(ChromotingHostContext* context,
                                       Capturer* capturer,
                                       EventExecutor* event_executor,
                                       Curtain* curtain,
                                       DisconnectWindow* disconnect_window,
                                       ContinueWindow* continue_window,
                                       LocalInputMonitor* local_input_monitor)
    : host_(NULL),
      context_(context),
      capturer_(capturer),
      event_executor_(event_executor),
      curtain_(curtain),
      disconnect_window_(disconnect_window),
      continue_window_(continue_window),
      local_input_monitor_(local_input_monitor),
      is_monitoring_local_inputs_(false),
      continue_timer_started_(false),
      proxy_(new UIThreadProxy(context)) {
}

DesktopEnvironment::~DesktopEnvironment() {
}

void DesktopEnvironment::Shutdown() {
  DCHECK(context_->IsUIThread());

  MonitorLocalInputs(false);
  ShowDisconnectWindow(false, std::string());
  ShowContinueWindow(false);
  StartContinueWindowTimer(false);

  proxy_->Detach();
}

void DesktopEnvironment::OnConnect(const std::string& username) {
  proxy_->CallOnUIThread(FROM_HERE, base::Bind(
      &DesktopEnvironment::ProcessOnConnect, base::Unretained(this), username));
}

void DesktopEnvironment::OnLastDisconnect() {
  proxy_->CallOnUIThread(FROM_HERE, base::Bind(
      &DesktopEnvironment::ProcessOnLastDisconnect, base::Unretained(this)));
}

void DesktopEnvironment::OnPause(bool pause) {
  proxy_->CallOnUIThread(FROM_HERE, base::Bind(
      &DesktopEnvironment::ProcessOnPause, base::Unretained(this), pause));
}

void DesktopEnvironment::ProcessOnConnect(const std::string& username) {
  DCHECK(context_->IsUIThread());

  MonitorLocalInputs(true);
  ShowDisconnectWindow(true, username);
  StartContinueWindowTimer(true);
}

void DesktopEnvironment::ProcessOnLastDisconnect() {
  DCHECK(context_->IsUIThread());

  MonitorLocalInputs(false);
  ShowDisconnectWindow(false, std::string());
  ShowContinueWindow(false);
  StartContinueWindowTimer(false);
}

void DesktopEnvironment::ProcessOnPause(bool pause) {
  StartContinueWindowTimer(!pause);
}

void DesktopEnvironment::MonitorLocalInputs(bool enable) {
  DCHECK(context_->IsUIThread());

  if (enable == is_monitoring_local_inputs_)
    return;
  if (enable) {
    local_input_monitor_->Start(host_);
  } else {
    local_input_monitor_->Stop();
  }
  is_monitoring_local_inputs_ = enable;
}

void DesktopEnvironment::ShowDisconnectWindow(bool show,
                                              const std::string& username) {
  DCHECK(context_->IsUIThread());

  if (show) {
    disconnect_window_->Show(host_, username);
  } else {
    disconnect_window_->Hide();
  }
}

void DesktopEnvironment::ShowContinueWindow(bool show) {
  DCHECK(context_->IsUIThread());

  if (show) {
    continue_window_->Show(host_);
  } else {
    continue_window_->Hide();
  }
}

void DesktopEnvironment::StartContinueWindowTimer(bool start) {
  DCHECK(context_->IsUIThread());

  if (start && !continue_timer_started_) {
    continue_timer_target_time_ = base::Time::Now() +
        base::TimeDelta::FromMilliseconds(kContinueWindowTimeoutMs);
    proxy_->CallOnUIThreadDelayed(
        FROM_HERE, base::Bind(&DesktopEnvironment::ContinueWindowTimerFunc,
                              base::Unretained(this)),
        kContinueWindowTimeoutMs);
  }

  continue_timer_started_ = start;
}

void DesktopEnvironment::ContinueWindowTimerFunc() {
  DCHECK(context_->IsUIThread());

  // This function may be called prematurely if timer was stopped and
  // then started again. In that case we just ignore this call.
  if (continue_timer_target_time_ > base::Time::Now())
    return;

  continue_timer_started_ = false;
  host_->PauseSession(true);
  ShowContinueWindow(true);
}

}  // namespace remoting
<|endoftext|>


<commit_before>/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
 *****************************************************************************
 *
 * File:         MemoryMonitor.cpp
 * Description:  Methods to detect memory pressure from the operating system.
 *               On NT, a separate thread is doing this work, on NSK the
 *               pressure is detected between subsequent calls.
 *
 * Created:      8/2/99
 * Modified:
 * Language:     C++
 *
 *
 *
 *****************************************************************************
 */

#include "Platform.h"
#include "memorymonitor.h"
#include "ComRtUtils.h"
#include "NAAssert.h"
#include "PortProcessCalls.h"

#include <time.h>

#include <cextdecs/cextdecs.h>
#undef DllImport
#define DllImport __declspec( dllimport )

// fix a problem with different versions of pdh.dll
#ifdef PdhOpenQuery
#undef PdhOpenQuery   //       PdhOpenQueryA or PdhOpenQueryW
extern "C" Lng32 __stdcall
PdhOpenQuery (LPCSTR  szD, DWORD  dw, HQUERY  *phQ );
#endif

//SQ_LINUX #ifdef NA_WINNT

NABoolean MemoryMonitor::threadIsCreated_ = 0;
HANDLE MemoryMonitor::updateThread_ = (HANDLE) 0;
ULng32 MemoryMonitor::threadId_ = 0;

DWORD WINAPI memMonitorUpdateThread(void * param) {
  // params points to the memory monitor object
  MemoryMonitor *memMonitor = (MemoryMonitor*) param;
  Lng32 sleepTime = memMonitor->getSampleInterval();
  float scale = 1.0;
  while (TRUE) {
    memMonitor->update(scale);
    Sleep((ULng32)(sleepTime * scale));
  };
  return 0;
};

MemoryMonitor::MemoryMonitor(Lng32 windowSize,
			     Lng32 sampleInterval,
			     CollHeap *heap)
  : physKBytes_(0),
    availBytesPercent_(1.0),
    commitBytesPercent_(0),
    commitPhysRatio_(0),

    pagingCounterAdded_(FALSE),
    pageFaultRate_(0),
    prevPageFault_(0),
    prevTime_(0),
    entryCount_(1),
    resetEntryCount_(TRUE),
    resetOnce_(FALSE),

    enable_(TRUE),
    pressure_(0),

    sampleInterval_(sampleInterval * 1000)
{
  // if the windowSize is 0, we do not need memory monitor.
  assert(windowSize);
  char buffer[1024];
  char *currPtr;
  size_t bytesRead;
  fd_meminfo_ = fopen("/proc/meminfo", "r");
  if (fd_meminfo_) {
    bytesRead = fread(buffer, 1, 1024, fd_meminfo_);
    currPtr = strstr(buffer, "MemTotal");
    if (currPtr) {
      sscanf(currPtr, "%*s " PF64 " kB", &memTotal_);
      physKBytes_ = memTotal_;
      physKBytesRatio_ = physKBytes_ / (8 * 1024 * 1024);
    }
    else {
      // something unexpected. let's just close the file
      fclose(fd_meminfo_);
      fd_meminfo_ = 0;
    }
  }

  // Disable monitoring if the envvar is set.
  // We do this here to get the initial meminfo when the
  //
  char *lv_envVar = getenv("SQL_DISABLE_MEMMONITOR");
  if (lv_envVar && (strcmp(lv_envVar, "1") == 0)) {
    return;
  }

  ULng32 pageSize = 0;

  fd_vmstat_ = fopen("/proc/vmstat", "r");

  if (!threadIsCreated_)
    {
      // and finally start the update thread
      updateThread_ = CreateNewThread(
                           &memMonitorUpdateThread, // Thread func
                           this );   // Argument for thread
      threadIsCreated_ = TRUE;
    }

};

MemoryMonitor::~MemoryMonitor() {

//SQ_LINUX #ifdef NA_WINNT
  if (fd_meminfo_)
  {
    fclose(fd_meminfo_);
    fclose(fd_vmstat_);
  }
};

// Called by main thread only.
Lng32 MemoryMonitor::memoryPressure() {

//SQ_LINUX #ifdef NA_WINNT

  return pressure_;
};

// - Compute weighted running average for pageFaultRate
//   (# of disk writes per second).
// - Start a new cycle when the main thread sees the pressure.
// [Eric]
void MemoryMonitor::updatePageFaultRate(Int64 pageFault) {

  float delta = (float)(pageFault - prevPageFault_);
  if (delta < 0)
    return;

  Int64 currTime = JULIANTIMESTAMP(OMIT,OMIT,OMIT,OMIT);

  // Just in case
  if (currTime <= prevTime_)
    return;

  if (resetEntryCount_)
    { // Start a new cycle after the main thread sees pressure peek.
      resetEntryCount_ = FALSE;
      entryCount_ = 1;
      prevPageFault_ = pageFault;
      prevTime_ = currTime;
      return;
    }

  float ratio = (float)(1.0 / entryCount_);
#pragma warning (disable : 4244)   //warning elimination
#pragma nowarn(1506)   // warning elimination
  pageFaultRate_ = (1 - ratio) * pageFaultRate_ + ratio *
                   delta / ((float)(currTime - prevTime_) / 1E6);
#pragma warn(1506)  // warning elimination
#pragma warning (default : 4244)   //warning elimination
  prevPageFault_ = pageFault;
  prevTime_ = currTime;
  if (entryCount_ < 3)
    entryCount_++;
}

void MemoryMonitor::update(float &scale) {

	if (fd_meminfo_ == NULL)
		return; // error handling here.
        Int32 success = fseek(fd_meminfo_, 0, SEEK_SET);
        if (success != 0)
                return;
	char buffer[4096];
	Int64 memFree = -1, memCommitAS = 0;
	Int64 pgpgout = -1, pgpgin = -1;
	size_t bytesRead;
	char * currPtr;
        bytesRead = fread(buffer, 1, 2048, fd_meminfo_);
        // Make sure there wasn't an error (next fseek will clear eof)
        if (!feof(fd_meminfo_))// Make sure there wasn't an error
        {
	        scale = 6;
		pressure_ = 0;
		return;
        }
        currPtr = strstr(buffer, "MemFree");
	if (currPtr) sscanf(currPtr, "%*s " PF64 " kB", &memFree);
        currPtr = strstr(buffer, "Committed_AS");
	if (currPtr) sscanf(currPtr, "%*s " PF64 " kB", &memCommitAS);

	Lng32 prevPressure = pressure_;
	if (memTotal_ > 0 && memCommitAS > 0 && memFree > -1)
		commitPhysRatio_ = (float)memCommitAS / (float) memTotal_;
	else
	{
	        scale = 6;
		pressure_ = 0;
		return;
	}
        if(memFree > 0)
        {
          memFree_ = memFree;
        }
        else
        {
           memFree_ = 0;
           return;
        }

	if (fd_vmstat_ == NULL)
		return; // error handling here.
        success = fseek(fd_vmstat_, 0, SEEK_SET);
        if (success != 0)
	{
	        scale = 6;
		pressure_ = 0;
		return;
	}
	bytesRead = fread(buffer, 1, 2048, fd_vmstat_);
        if (!feof(fd_vmstat_))
        {
	        scale = 6;
		pressure_ = 0;
		return;
        }
        currPtr = strstr(buffer, "pgpgin");
	if (currPtr) sscanf(currPtr, "%*s " PF64 " kB", &pgpgin);
        currPtr = strstr(buffer, "pgpgout");
	if (currPtr) sscanf(currPtr, "%*s " PF64 " kB", &pgpgout);
	if (pgpgin > -1 && pgpgout > -1)
	  updatePageFaultRate(pgpgin + pgpgout);
	else
	{
	        scale = 6;
		pressure_ = 0;
		return;
	}
        float percentFree = (float)memFree / (float)memTotal_;
        float normalizedPageFaultRate = pageFaultRate_ / physKBytesRatio_;
        pressure_ = MAXOF(MINOF(((1 - 4 * percentFree) * (normalizedPageFaultRate / 25) * commitPhysRatio_), 100), 0);
	scale = 1 + (100 - pressure_) * 0.05;
	return;
}

<commit_msg>updates for [TRAFODION-1492] - address review comments.<commit_after>/**********************************************************************
// @@@ START COPYRIGHT @@@
//
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements.  See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership.  The ASF licenses this file
// to you 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.
//
// @@@ END COPYRIGHT @@@
**********************************************************************/
/* -*-C++-*-
 *****************************************************************************
 *
 * File:         MemoryMonitor.cpp
 * Description:  Methods to detect memory pressure from the operating system.
 *               On NT, a separate thread is doing this work, on NSK the
 *               pressure is detected between subsequent calls.
 *
 * Created:      8/2/99
 * Modified:
 * Language:     C++
 *
 *
 *
 *****************************************************************************
 */

#include "Platform.h"
#include "memorymonitor.h"
#include "ComRtUtils.h"
#include "NAAssert.h"
#include "PortProcessCalls.h"

#include <time.h>

#include <cextdecs/cextdecs.h>
#undef DllImport
#define DllImport __declspec( dllimport )

// fix a problem with different versions of pdh.dll
#ifdef PdhOpenQuery
#undef PdhOpenQuery   //       PdhOpenQueryA or PdhOpenQueryW
extern "C" Lng32 __stdcall
PdhOpenQuery (LPCSTR  szD, DWORD  dw, HQUERY  *phQ );
#endif

//SQ_LINUX #ifdef NA_WINNT

NABoolean MemoryMonitor::threadIsCreated_ = 0;
HANDLE MemoryMonitor::updateThread_ = (HANDLE) 0;
ULng32 MemoryMonitor::threadId_ = 0;

DWORD WINAPI memMonitorUpdateThread(void * param) {
  // params points to the memory monitor object
  MemoryMonitor *memMonitor = (MemoryMonitor*) param;
  Lng32 sleepTime = memMonitor->getSampleInterval();
  float scale = 1.0;
  while (TRUE) {
    memMonitor->update(scale);
    Sleep((ULng32)(sleepTime * scale));
  };
  return 0;
};

MemoryMonitor::MemoryMonitor(Lng32 windowSize,
			     Lng32 sampleInterval,
			     CollHeap *heap)
  : physKBytes_(0),
    physKBytesRatio_(0),
    availBytesPercent_(1.0),
    commitBytesPercent_(0),
    commitPhysRatio_(0),

    pagingCounterAdded_(FALSE),
    pageFaultRate_(0),
    prevPageFault_(0),
    prevTime_(0),
    entryCount_(1),
    resetEntryCount_(TRUE),
    resetOnce_(FALSE),

    enable_(TRUE),
    pressure_(0),

    sampleInterval_(sampleInterval * 1000)
{
  // if the windowSize is 0, we do not need memory monitor.
  assert(windowSize);
  char buffer[1024];
  char *currPtr;
  size_t bytesRead;
  fd_meminfo_ = fopen("/proc/meminfo", "r");
  if (fd_meminfo_) {
    bytesRead = fread(buffer, 1, 1024, fd_meminfo_);
    currPtr = strstr(buffer, "MemTotal");
    if (currPtr) {
      sscanf(currPtr, "%*s " PF64 " kB", &memTotal_);
      physKBytes_ = memTotal_;
      physKBytesRatio_ = physKBytes_ / (8 * 1024 * 1024);
    }
    else {
      // something unexpected. let's just close the file
      fclose(fd_meminfo_);
      fd_meminfo_ = 0;
    }
  }

  // Disable monitoring if the envvar is set.
  // We do this here to get the initial meminfo
  // even if one wants to disable continous memory
  // monitoring.
  char *lv_envVar = getenv("SQL_DISABLE_MEMMONITOR");
  if (lv_envVar && (strcmp(lv_envVar, "1") == 0)) {
    return;
  }

  ULng32 pageSize = 0;

  fd_vmstat_ = fopen("/proc/vmstat", "r");

  if (!threadIsCreated_)
    {
      // and finally start the update thread
      updateThread_ = CreateNewThread(
                           &memMonitorUpdateThread, // Thread func
                           this );   // Argument for thread
      threadIsCreated_ = TRUE;
    }

};

MemoryMonitor::~MemoryMonitor() {

//SQ_LINUX #ifdef NA_WINNT
  if (fd_meminfo_)
  {
    fclose(fd_meminfo_);
    fclose(fd_vmstat_);
  }
};

// Called by main thread only.
Lng32 MemoryMonitor::memoryPressure() {

//SQ_LINUX #ifdef NA_WINNT

  return pressure_;
};

// - Compute weighted running average for pageFaultRate
//   (# of disk writes per second).
// - Start a new cycle when the main thread sees the pressure.
// [Eric]
void MemoryMonitor::updatePageFaultRate(Int64 pageFault) {

  float delta = (float)(pageFault - prevPageFault_);
  if (delta < 0)
    return;

  Int64 currTime = JULIANTIMESTAMP(OMIT,OMIT,OMIT,OMIT);

  // Just in case
  if (currTime <= prevTime_)
    return;

  if (resetEntryCount_)
    { // Start a new cycle after the main thread sees pressure peek.
      resetEntryCount_ = FALSE;
      entryCount_ = 1;
      prevPageFault_ = pageFault;
      prevTime_ = currTime;
      return;
    }

  float ratio = (float)(1.0 / entryCount_);
#pragma warning (disable : 4244)   //warning elimination
#pragma nowarn(1506)   // warning elimination
  pageFaultRate_ = (1 - ratio) * pageFaultRate_ + ratio *
                   delta / ((float)(currTime - prevTime_) / 1E6);
#pragma warn(1506)  // warning elimination
#pragma warning (default : 4244)   //warning elimination
  prevPageFault_ = pageFault;
  prevTime_ = currTime;
  if (entryCount_ < 3)
    entryCount_++;
}

void MemoryMonitor::update(float &scale) {

	if (fd_meminfo_ == NULL)
		return; // error handling here.
        Int32 success = fseek(fd_meminfo_, 0, SEEK_SET);
        if (success != 0)
                return;
	char buffer[4096];
	Int64 memFree = -1, memCommitAS = 0;
	Int64 pgpgout = -1, pgpgin = -1;
	size_t bytesRead;
	char * currPtr;
        bytesRead = fread(buffer, 1, 2048, fd_meminfo_);
        // Make sure there wasn't an error (next fseek will clear eof)
        if (!feof(fd_meminfo_))// Make sure there wasn't an error
        {
	        scale = 6;
		pressure_ = 0;
		return;
        }
        currPtr = strstr(buffer, "MemFree");
	if (currPtr) sscanf(currPtr, "%*s " PF64 " kB", &memFree);
        currPtr = strstr(buffer, "Committed_AS");
	if (currPtr) sscanf(currPtr, "%*s " PF64 " kB", &memCommitAS);

	Lng32 prevPressure = pressure_;
	if (memTotal_ > 0 && memCommitAS > 0 && memFree > -1)
		commitPhysRatio_ = (float)memCommitAS / (float) memTotal_;
	else
	{
	        scale = 6;
		pressure_ = 0;
		return;
	}
        if(memFree > 0)
        {
          memFree_ = memFree;
        }
        else
        {
           memFree_ = 0;
           return;
        }

	if (fd_vmstat_ == NULL)
		return; // error handling here.
        success = fseek(fd_vmstat_, 0, SEEK_SET);
        if (success != 0)
	{
	        scale = 6;
		pressure_ = 0;
		return;
	}
	bytesRead = fread(buffer, 1, 2048, fd_vmstat_);
        if (!feof(fd_vmstat_))
        {
	        scale = 6;
		pressure_ = 0;
		return;
        }
        currPtr = strstr(buffer, "pgpgin");
	if (currPtr) sscanf(currPtr, "%*s " PF64 " kB", &pgpgin);
        currPtr = strstr(buffer, "pgpgout");
	if (currPtr) sscanf(currPtr, "%*s " PF64 " kB", &pgpgout);
	if (pgpgin > -1 && pgpgout > -1)
	  updatePageFaultRate(pgpgin + pgpgout);
	else
	{
	        scale = 6;
		pressure_ = 0;
		return;
	}
        float percentFree = (float)memFree / (float)memTotal_;
        float normalizedPageFaultRate = pageFaultRate_ / physKBytesRatio_;
        pressure_ = MAXOF(MINOF(((1 - 4 * percentFree) * (normalizedPageFaultRate / 25) * commitPhysRatio_), 100), 0);
	scale = 1 + (100 - pressure_) * 0.05;
	return;
}

<|endoftext|>


<commit_before>/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*
* 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 "ODUPCAReader.h"
#include "Result.h"

namespace ZXing {
namespace OneD {

static Result MaybeReturnResult(Result&& result)
{
	const std::wstring& text = result.text();
	if (!text.empty() && text[0] == '0') {
		result.setText(text.substr(1));
		result.setFormat(BarcodeFormat::UPC_A);
		return result;
	}
	else {
		return Result(DecodeStatus::FormatError);
	}
}

Result
UPCAReader::decodeRow(int rowNumber, const BitArray& row, std::unique_ptr<DecodingState>& state) const
{
	return MaybeReturnResult(_reader.decodeRow(rowNumber, row, state));
}

Result
UPCAReader::decodeRow(int rowNumber, const BitArray& row, BitArray::Range startGuard) const
{
	return MaybeReturnResult(_reader.decodeRow(rowNumber, row, startGuard));
}

BarcodeFormat
UPCAReader::expectedFormat() const
{
	return BarcodeFormat::UPC_A;
}

BitArray::Range
UPCAReader::decodeMiddle(const BitArray& row, BitArray::Iterator begin, std::string& resultString) const
{
	return _reader.decodeMiddle(row, begin, resultString);
}

} // OneD
} // ZXing
<commit_msg>Fix a warning return-std-move<commit_after>/*
* Copyright 2016 Nu-book Inc.
* Copyright 2016 ZXing authors
*
* 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 "ODUPCAReader.h"
#include "Result.h"

namespace ZXing {
namespace OneD {

static Result MaybeReturnResult(Result&& result)
{
	const std::wstring& text = result.text();
	if (!text.empty() && text[0] == '0') {
		result.setText(text.substr(1));
		result.setFormat(BarcodeFormat::UPC_A);
		return std::move(result);
	}
	else {
		return Result(DecodeStatus::FormatError);
	}
}

Result
UPCAReader::decodeRow(int rowNumber, const BitArray& row, std::unique_ptr<DecodingState>& state) const
{
	return MaybeReturnResult(_reader.decodeRow(rowNumber, row, state));
}

Result
UPCAReader::decodeRow(int rowNumber, const BitArray& row, BitArray::Range startGuard) const
{
	return MaybeReturnResult(_reader.decodeRow(rowNumber, row, startGuard));
}

BarcodeFormat
UPCAReader::expectedFormat() const
{
	return BarcodeFormat::UPC_A;
}

BitArray::Range
UPCAReader::decodeMiddle(const BitArray& row, BitArray::Iterator begin, std::string& resultString) const
{
	return _reader.decodeMiddle(row, begin, resultString);
}

} // OneD
} // ZXing
<|endoftext|>


<commit_before>#include <utility/Exception.hpp>
#include <utility/Logging.hpp>

#include <algorithm>

namespace Utility
{
    void rethrow(const std::string & message, const char * file, unsigned int line, const std::string & function)
    {
        try
        {
            std::rethrow_exception(std::current_exception());
        }
        catch( const S_Exception & ex )
        {
            auto ex2 = S_Exception(ex.classifier, ex.level, message, file, line, function);
            std::throw_with_nested(ex2);
        }
        catch (const std::exception & ex)
        {
            auto ex2 = S_Exception(Exception_Classifier::Standard_Exception, Log_Level::Severe, message, file, line, function);
            std::throw_with_nested(ex2);
        }
        catch (...)
        {
            auto ex = S_Exception(Exception_Classifier::Unknown_Exception, Log_Level::Severe, message, file, line, function);
            std::throw_with_nested(ex);
        }
    }

    void Backtrace_Exception()
    {
        try
        {
            if ( std::exception_ptr eptr = std::current_exception() )
            {
                std::rethrow_exception( eptr );
            }
            else
            {
                Log( Log_Level::Severe, Log_Sender::API, "Unknown Exception. Terminating" );
                Log.Append_to_File();
                std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
            }
        }
        catch ( const S_Exception & ex )
        {
            Log( ex.level, Log_Sender::API, std::string(ex.what()));
            try
            {
                rethrow_if_nested(ex);
            }
            catch( ... )
            {
                Backtrace_Exception();
            }
        }
        catch ( const std::exception & ex )
        {
            Log( Log_Level::Severe, Log_Sender::API, fmt::format("Caught std::exception \"{}\"", ex.what()) );
            try
            {
                rethrow_if_nested(ex);
            }
            catch( ... )
            {
                Backtrace_Exception();
            }
        }
    }

    void Handle_Exception_API( const char * file, unsigned int line, const std::string & api_function, int idx_image, int idx_chain )
    {
        try
        {
            // Rethrow in order to get an exception reference (instead of pointer)
            try
            {
                std::rethrow_exception(std::current_exception());
            }
            catch( const S_Exception & ex )
            {
                Log( ex.level, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain );
                std::string str_exception;
                if (int(ex.level) > 1)
                    str_exception = "exception";
                else
                    str_exception = "SEVERE exception";
                Log(ex.level, Log_Sender::API, fmt::format("Caught {} in API function \'{}\' (at {}:{})\n{:>49}Exception backtrace:", str_exception, api_function, file, line, " "), idx_image, idx_chain);

                // Create backtrace
                Backtrace_Exception();
                Log(ex.level, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain);

                // Check if the exception was recoverable
                if (ex.classifier == Exception_Classifier::Unknown_Exception ||
                    ex.classifier == Exception_Classifier::System_not_Initialized ||
                    ex.classifier == Exception_Classifier::Simulated_domain_too_small ||
                    ex.classifier == Exception_Classifier::CUDA_Error ||
                    int(ex.level) <= 1)
                {
                    Log( Log_Level::Severe, Log_Sender::API, "TERMINATING!", idx_image, idx_chain );
                    Log.Append_to_File();
                    std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
                }

                // If it was recoverable we now write to Log
                Log.Append_to_File();
            }
            catch ( const std::exception & ex )
            {
                std::cerr << "Caught std::exception in API function \'" << api_function << "\'" << std::endl;
                std::cerr << "Unable to handle std::exception \'" << ex.what() << "\'! TERMINATING!" << std::endl;
                std::exit(EXIT_FAILURE);  // exit the application. may lead to data loss
            }
            catch ( ... )
            {
                std::cerr << "Caught unknown exception in API function \'" << api_function << "\'" << std::endl;
                std::cerr << "Unable to handle! TERMINATING!" << std::endl;
                std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
            }
        }
        catch ( ... )
        {
            std::cerr << "Something went super-wrong! TERMINATING!" << std::endl;
            std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
        }
    }

    void Handle_Exception_Core(std::string message, const char * file, unsigned int line, const std::string & function)
    {
        // Rethrow in order to get an exception reference (instead of pointer)
        try
        {
            std::rethrow_exception(std::current_exception());
        }
        catch (const S_Exception & ex)
        {
            bool can_handle = true;
            if (ex.classifier == Exception_Classifier::Unknown_Exception ||
                ex.classifier == Exception_Classifier::System_not_Initialized ||
                ex.classifier == Exception_Classifier::Simulated_domain_too_small ||
                ex.classifier == Exception_Classifier::CUDA_Error ||
                int(ex.level) <= 1)
                can_handle = false;

            if (can_handle)
            {
                int idx_image = -1, idx_chain = -1;

                Log(ex.level, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain);
                Log(ex.level, Log_Sender::API, fmt::format("{}:{} in function \'{}\'\n{:>49}Caught exception: {}\n{:>49}Exception backtrace:", file, line, function, " ", message, " "), idx_image, idx_chain);

                // Create backtrace
                Backtrace_Exception();
                Log(ex.level, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain);
                Log.Append_to_File();
            }
            else
            {
                auto ex2 = S_Exception(ex.classifier, ex.level, message, file, line, function);
                std::throw_with_nested(ex2);
            }
        }
        catch (...)
        {
            // If something cannot be handled in the core, we re-throw it
            // so it will be handled in the API layer
            spirit_rethrow(message);
        }
    }

    // void Spirit_Exception( const Exception & ex, int idx_image, int idx_chain )
    // {
    //     switch ( ex )
    //     {
    //         case Exception::File_not_Found :
    //             Log( Log_Level::Warning, Log_Sender::API, "File not found. Unable to open.",
    //                  idx_image, idx_chain );
    //             break;

    //         case Exception::System_not_Initialized :
    //             Log( Log_Level::Severe, Log_Sender::API, "System is uninitialized. Terminating.", idx_image, idx_chain );
    //             Log.Append_to_File();
    //             std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
    //             break;

    //         case Exception::Division_by_zero:
    //             Log( Log_Level::Severe, Log_Sender::API, "Division by zero", idx_image, idx_chain );
    //             Log.Append_to_File();
    //             std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
    //             break;

    //         case Exception::Simulated_domain_too_small:
    //             Log( Log_Level::Error, Log_Sender::API, std::string( "Simulated domain is " ) +
    //                  std::string( "too small. No action taken." ), idx_image, idx_chain );
    //             break;

    //         case Exception::Not_Implemented:
    //             Log( Log_Level::Warning, Log_Sender::API, std::string( "Feature not " ) +
    //                  std::string( " implemented. No action taken." ), idx_image, idx_chain );
    //             break;

    //         case Exception::Non_existing_Image:
    //             Log( Log_Level::Warning, Log_Sender::API, "Non existing image. No action taken.",
    //                  idx_image, idx_chain );
    //             break;

    //         case Exception::Non_existing_Chain:
    //             Log( Log_Level::Warning, Log_Sender::API, "Non existing chain. No action taken.",
    //                  idx_image, idx_chain );
    //             break;
    //     }
    // }
}
<commit_msg>Core: improved logging of unhandled exceptions. They are now Logged as well, and if that fails (e.g. due to the Logger being broken) the last catch will still print some useful info.<commit_after>#include <utility/Exception.hpp>
#include <utility/Logging.hpp>

#include <algorithm>

namespace Utility
{
    void rethrow(const std::string & message, const char * file, unsigned int line, const std::string & function)
    try
    {
        std::rethrow_exception(std::current_exception());
    }
    catch( const S_Exception & ex )
    {
        auto ex2 = S_Exception(ex.classifier, ex.level, message, file, line, function);
        std::throw_with_nested(ex2);
    }
    catch (const std::exception & ex)
    {
        auto ex2 = S_Exception(Exception_Classifier::Standard_Exception, Log_Level::Severe, message, file, line, function);
        std::throw_with_nested(ex2);
    }
    catch (...)
    {
        auto ex = S_Exception(Exception_Classifier::Unknown_Exception, Log_Level::Severe, message, file, line, function);
        std::throw_with_nested(ex);
    }

    void Backtrace_Exception()
    try
    {
        if ( std::exception_ptr eptr = std::current_exception() )
        {
            std::rethrow_exception( eptr );
        }
        else
        {
            Log( Log_Level::Severe, Log_Sender::API, "Unknown Exception. Terminating" );
            Log.Append_to_File();
            std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
        }
    }
    catch ( const S_Exception & ex )
    {
        Log( ex.level, Log_Sender::API, std::string(ex.what()));
        try
        {
            rethrow_if_nested(ex);
        }
        catch( ... )
        {
            Backtrace_Exception();
        }
    }
    catch ( const std::exception & ex )
    {
        Log( Log_Level::Severe, Log_Sender::API, fmt::format("std::exception: \"{}\"", ex.what()) );
        try
        {
            rethrow_if_nested(ex);
        }
        catch( ... )
        {
            Backtrace_Exception();
        }
    }

    void Handle_Exception_API( const char * file, unsigned int line, const std::string & api_function, int idx_image, int idx_chain )
    try
    {
        // Rethrow in order to get an exception reference (instead of pointer)
        try
        {
            std::rethrow_exception(std::current_exception());
        }
        catch( const S_Exception & ex )
        {
            Log( ex.level, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain );
            std::string str_exception;
            if (int(ex.level) > 1)
                str_exception = "exception";
            else
                str_exception = "SEVERE exception";
            Log(ex.level, Log_Sender::API, fmt::format(
                "Caught {} in API function \'{}\' (at {}:{})\n{:>49}Exception backtrace:", str_exception, api_function, file, line, " "), idx_image, idx_chain);

            // Create backtrace
            Backtrace_Exception();
            Log(ex.level, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain);

            // Check if the exception was recoverable
            if (ex.classifier == Exception_Classifier::Unknown_Exception ||
                ex.classifier == Exception_Classifier::System_not_Initialized ||
                ex.classifier == Exception_Classifier::Simulated_domain_too_small ||
                ex.classifier == Exception_Classifier::CUDA_Error ||
                int(ex.level) <= 1)
            {
                Log( Log_Level::Severe, Log_Sender::API, "TERMINATING!", idx_image, idx_chain );
                Log.Append_to_File();
                std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
            }

            // If it was recoverable we now write to Log
            Log.Append_to_File();
        }
        catch ( const std::exception & ex )
        {
            Log( Log_Level::Severe, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain );
            Log( Log_Level::Severe, Log_Sender::API, fmt::format(
                "Caught std::exception in API function \'{}\' (at {}:{})\n{:>49}Exception backtrace:", api_function, file, line, " "), idx_image, idx_chain);
            // Create backtrace
            Backtrace_Exception();
            Log( Log_Level::Severe, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain);

            // Terminate
            Log( Log_Level::Severe, Log_Sender::API, "TERMINATING!", idx_image, idx_chain );
            Log.Append_to_File();
            std::exit(EXIT_FAILURE);  // exit the application. may lead to data loss
        }
        catch ( ... )
        {
            Log( Log_Level::Severe, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain );
            Log( Log_Level::Severe, Log_Sender::API, fmt::format(
                "Caught unknown exception in API function \'{}\' (at {}:{})\n{:>49}Cannot backtrace unknown exceptions...", api_function, file, line, " "), idx_image, idx_chain);
            Log( Log_Level::Severe, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain);
            Log( Log_Level::Severe, Log_Sender::API, "Unable to handle! TERMINATING!", idx_image, idx_chain );
            Log.Append_to_File();
            std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
        }
    }
    catch ( ... )
    {
        std::cerr << "Another exception occurred while handling an exception from \'" << api_function << "\' (at " << file << ":" << line << ")!" << std::endl;
        std::cerr << "TERMINATING!" << std::endl;
        std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
    }

    void Handle_Exception_Core(std::string message, const char * file, unsigned int line, const std::string & function)
    try
    {
        // Rethrow in order to get an exception reference (instead of pointer)
        std::rethrow_exception(std::current_exception());
    }
    catch (const S_Exception & ex)
    {
        bool can_handle = true;
        if (ex.classifier == Exception_Classifier::Unknown_Exception ||
            ex.classifier == Exception_Classifier::System_not_Initialized ||
            ex.classifier == Exception_Classifier::Simulated_domain_too_small ||
            ex.classifier == Exception_Classifier::CUDA_Error ||
            int(ex.level) <= 1)
            can_handle = false;

        if (can_handle)
        {
            int idx_image = -1, idx_chain = -1;

            Log(ex.level, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain);
            Log(ex.level, Log_Sender::API, fmt::format(
                "{}:{} in function \'{}\'\n{:>49}Caught exception: {}\n{:>49}Exception backtrace:", file, line, function, " ", message, " "), idx_image, idx_chain);

            // Create backtrace
            Backtrace_Exception();
            Log(ex.level, Log_Sender::API, "-----------------------------------------------------", idx_image, idx_chain);
            Log.Append_to_File();
        }
        else
        {
            auto ex2 = S_Exception(ex.classifier, ex.level, message, file, line, function);
            std::throw_with_nested(ex2);
        }
    }
    catch (...)
    {
        // If something cannot be handled in the core, we re-throw it
        // so it will be handled in the API layer
        spirit_rethrow(message);
    }

    // void Spirit_Exception( const Exception & ex, int idx_image, int idx_chain )
    // {
    //     switch ( ex )
    //     {
    //         case Exception::File_not_Found :
    //             Log( Log_Level::Warning, Log_Sender::API, "File not found. Unable to open.",
    //                  idx_image, idx_chain );
    //             break;

    //         case Exception::System_not_Initialized :
    //             Log( Log_Level::Severe, Log_Sender::API, "System is uninitialized. Terminating.", idx_image, idx_chain );
    //             Log.Append_to_File();
    //             std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
    //             break;

    //         case Exception::Division_by_zero:
    //             Log( Log_Level::Severe, Log_Sender::API, "Division by zero", idx_image, idx_chain );
    //             Log.Append_to_File();
    //             std::exit( EXIT_FAILURE );  // exit the application. may lead to data loss
    //             break;

    //         case Exception::Simulated_domain_too_small:
    //             Log( Log_Level::Error, Log_Sender::API, std::string( "Simulated domain is " ) +
    //                  std::string( "too small. No action taken." ), idx_image, idx_chain );
    //             break;

    //         case Exception::Not_Implemented:
    //             Log( Log_Level::Warning, Log_Sender::API, std::string( "Feature not " ) +
    //                  std::string( " implemented. No action taken." ), idx_image, idx_chain );
    //             break;

    //         case Exception::Non_existing_Image:
    //             Log( Log_Level::Warning, Log_Sender::API, "Non existing image. No action taken.",
    //                  idx_image, idx_chain );
    //             break;

    //         case Exception::Non_existing_Chain:
    //             Log( Log_Level::Warning, Log_Sender::API, "Non existing chain. No action taken.",
    //                  idx_image, idx_chain );
    //             break;
    //     }
    // }
}
<|endoftext|>


<commit_before>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2016 Couchbase, 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 "config.h"

#include <platform/dirutils.h>

#include "callbacks.h"
#include "compress.h"
#include "kvstore.h"
#include "couch-kvstore/couch-kvstore.h"

#include <gtest/gtest.h>
#include <unordered_map>

extern "C" {
    static rel_time_t basic_current_time(void) {
        return 0;
    }

    rel_time_t (*ep_current_time)() = basic_current_time;

    time_t ep_real_time() {
        return time(NULL);
    }
}

class WriteCallback : public Callback<mutation_result> {
public:
    WriteCallback() {}

    void callback(mutation_result &result) {

    }

};

class StatsCallback : public Callback<kvstats_ctx> {
public:
    StatsCallback() {}

    void callback(kvstats_ctx &result) {

    }

};

class CacheCallback : public Callback<CacheLookup> {
public:
    CacheCallback(int64_t s, int64_t e, uint16_t vbid) :
        start(s), end(e), vb(vbid) { }

    void callback(CacheLookup &lookup) {
        EXPECT_EQ(vb, lookup.getVBucketId());
        EXPECT_LE(start, lookup.getBySeqno());
        EXPECT_LE(lookup.getBySeqno(), end);
    }

private:
    int64_t start;
    int64_t end;
    uint16_t vb;
};

class GetCallback : public Callback<GetValue> {
public:
    GetCallback() :
        expectCompressed(false) { }

    GetCallback(bool expect_compressed) :
        expectCompressed(expect_compressed) { }

    void callback(GetValue &result) {
        if (expectCompressed) {
            EXPECT_EQ(PROTOCOL_BINARY_DATATYPE_COMPRESSED,
                      result.getValue()->getDataType());
            snap_buf output;
            EXPECT_EQ(SNAP_SUCCESS,
                      doSnappyUncompress(result.getValue()->getData(),
                                         result.getValue()->getNBytes(),
                                         output));
            EXPECT_EQ(0,
                      strncmp("value",
                              output.buf.get(),
                              output.len));
        } else {
            EXPECT_EQ(0,
                      strncmp("value",
                              result.getValue()->getData(),
                              result.getValue()->getNBytes()));
        }
        delete result.getValue();
    }

private:
    bool expectCompressed;
};

// Creates and initializes a KVStore with the given config
static std::unique_ptr<KVStore> setup_kv_store(KVStoreConfig& config) {
    auto kvstore = std::unique_ptr<KVStore>(KVStoreFactory::create(config));

    StatsCallback sc;
    std::string failoverLog("");
    vbucket_state state(vbucket_state_active, 0, 0, 0, 0, 0, 0, 0, 0,
                        failoverLog);
    kvstore->snapshotVBucket(0, state, &sc);

    return kvstore;
}

/* Test callback for stats handling.
 * 'cookie' is a std::unordered_map<std::string, std::string) which stats
 * are accumulated in.
 */
static void add_stat_callback(const char *key, const uint16_t klen,
                              const char *val, const uint32_t vlen,
                              const void *cookie) {
    auto* map = reinterpret_cast<std::map<std::string, std::string>*>(
            const_cast<void*>(cookie));
    ASSERT_NE(nullptr, map);
    map->emplace(std::string(key, klen), std::string(val, vlen));
}

class CouchAndForestTest : public ::testing::TestWithParam<std::string> {
};

class CouchKVStoreTest : public ::testing::TestWithParam<std::string> {
};

/* Test basic set / get of a document */
TEST_P(CouchAndForestTest, BasicTest) {
    std::string data_dir("/tmp/kvstore-test");
    CouchbaseDirectoryUtilities::rmrf(data_dir.c_str());

    KVStoreConfig config(1024, 4, data_dir, GetParam(), 0);
    auto kvstore = setup_kv_store(config);

    kvstore->begin();

    Item item("key", 3, 0, 0, "value", 5);
    WriteCallback wc;
    kvstore->set(item, wc);

    EXPECT_TRUE(kvstore->commit(nullptr));

    GetCallback gc;
    kvstore->get("key", 0, gc);
}

TEST(CouchKVStoreTest, CompressedTest) {
    std::string data_dir("/tmp/kvstore-test");
    CouchbaseDirectoryUtilities::rmrf(data_dir.c_str());

    KVStoreConfig config(1024, 4, data_dir, "couchdb", 0);
    auto kvstore = setup_kv_store(config);

    kvstore->begin();

    uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES;
    WriteCallback wc;
    for (int i = 1; i <= 5; i++) {
        std::string key("key" + std::to_string(i));
        Item item(key.c_str(), key.length(),
                  0, 0, "value", 5, &datatype, 1, 0, i);
        kvstore->set(item, wc);
    }
    StatsCallback sc;
    kvstore->commit(&sc);

    std::shared_ptr<Callback<GetValue> > cb(new GetCallback(true));
    std::shared_ptr<Callback<CacheLookup> > cl(new CacheCallback(1, 5, 0));
    ScanContext* scanCtx;
    scanCtx = kvstore->initScanContext(cb, cl, 0, 1,
                                       DocumentFilter::ALL_ITEMS,
                                       ValueFilter::VALUES_COMPRESSED);

    ASSERT_NE(nullptr, scanCtx);
    EXPECT_EQ(scan_success, kvstore->scan(scanCtx));
    kvstore->destroyScanContext(scanCtx);
}

// Verify the stats returned from operations are accurate.
TEST(CouchKVStoreTest, StatsTest) {
    std::string data_dir("/tmp/kvstore-test");
    CouchbaseDirectoryUtilities::rmrf(data_dir.c_str());

    KVStoreConfig config(1024, 4, data_dir, "couchdb", 0);
    auto kvstore = setup_kv_store(config);

    // Perform a transaction with a single mutation (set) in it.
    kvstore->begin();
    const std::string key{"key"};
    const std::string value{"value"};
    Item item(key.c_str(), key.size(), 0, 0, value.c_str(), value.size());
    WriteCallback wc;
    kvstore->set(item, wc);

    StatsCallback sc;
    EXPECT_TRUE(kvstore->commit(&sc));
    // Check statistics are correct.
    std::map<std::string, std::string> stats;
    kvstore->addStats("", add_stat_callback, &stats);
    EXPECT_EQ("1", stats[":io_num_write"]);
    const size_t io_write_bytes = stoul(stats[":io_write_bytes"]);
    EXPECT_EQ(key.size() + value.size() + COUCHSTORE_METADATA_SIZE,
              io_write_bytes);

    // Hard to determine exactly how many bytes should have been written, but
    // expect non-zero, and least as many as the actual documents.
    const size_t io_total_write_bytes = stoul(stats[":io_total_write_bytes"]);
    EXPECT_GT(io_total_write_bytes, 0);
    EXPECT_GE(io_total_write_bytes, io_write_bytes);
}

// Test cases which run on both Couchstore and ForestDB
INSTANTIATE_TEST_CASE_P(CouchstoreAndForestDB,
                        CouchAndForestTest,
                        ::testing::Values("couchdb", "forestdb"));

static char allow_no_stats_env[] = "ALLOW_NO_STATS_UPDATE=yeah";

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    putenv(allow_no_stats_env);

    return RUN_ALL_TESTS();
}
<commit_msg>MB-14140: Fixup Debian7 build failure in baef8d3<commit_after>/* -*- Mode: C++; tab-width: 4; c-basic-offset: 4; indent-tabs-mode: nil -*- */
/*
 *     Copyright 2016 Couchbase, 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 "config.h"

#include <platform/dirutils.h>

#include "callbacks.h"
#include "compress.h"
#include "kvstore.h"
#include "couch-kvstore/couch-kvstore.h"

#include <gtest/gtest.h>
#include <unordered_map>

extern "C" {
    static rel_time_t basic_current_time(void) {
        return 0;
    }

    rel_time_t (*ep_current_time)() = basic_current_time;

    time_t ep_real_time() {
        return time(NULL);
    }
}

class WriteCallback : public Callback<mutation_result> {
public:
    WriteCallback() {}

    void callback(mutation_result &result) {

    }

};

class StatsCallback : public Callback<kvstats_ctx> {
public:
    StatsCallback() {}

    void callback(kvstats_ctx &result) {

    }

};

class CacheCallback : public Callback<CacheLookup> {
public:
    CacheCallback(int64_t s, int64_t e, uint16_t vbid) :
        start(s), end(e), vb(vbid) { }

    void callback(CacheLookup &lookup) {
        EXPECT_EQ(vb, lookup.getVBucketId());
        EXPECT_LE(start, lookup.getBySeqno());
        EXPECT_LE(lookup.getBySeqno(), end);
    }

private:
    int64_t start;
    int64_t end;
    uint16_t vb;
};

class GetCallback : public Callback<GetValue> {
public:
    GetCallback() :
        expectCompressed(false) { }

    GetCallback(bool expect_compressed) :
        expectCompressed(expect_compressed) { }

    void callback(GetValue &result) {
        if (expectCompressed) {
            EXPECT_EQ(PROTOCOL_BINARY_DATATYPE_COMPRESSED,
                      result.getValue()->getDataType());
            snap_buf output;
            EXPECT_EQ(SNAP_SUCCESS,
                      doSnappyUncompress(result.getValue()->getData(),
                                         result.getValue()->getNBytes(),
                                         output));
            EXPECT_EQ(0,
                      strncmp("value",
                              output.buf.get(),
                              output.len));
        } else {
            EXPECT_EQ(0,
                      strncmp("value",
                              result.getValue()->getData(),
                              result.getValue()->getNBytes()));
        }
        delete result.getValue();
    }

private:
    bool expectCompressed;
};

// Creates and initializes a KVStore with the given config
static std::unique_ptr<KVStore> setup_kv_store(KVStoreConfig& config) {
    auto kvstore = std::unique_ptr<KVStore>(KVStoreFactory::create(config));

    StatsCallback sc;
    std::string failoverLog("");
    vbucket_state state(vbucket_state_active, 0, 0, 0, 0, 0, 0, 0, 0,
                        failoverLog);
    kvstore->snapshotVBucket(0, state, &sc);

    return kvstore;
}

/* Test callback for stats handling.
 * 'cookie' is a std::unordered_map<std::string, std::string) which stats
 * are accumulated in.
 */
static void add_stat_callback(const char *key, const uint16_t klen,
                              const char *val, const uint32_t vlen,
                              const void *cookie) {
    auto* map = reinterpret_cast<std::map<std::string, std::string>*>(
            const_cast<void*>(cookie));
    ASSERT_NE(nullptr, map);
    map->insert(std::make_pair(std::string(key, klen),
                               std::string(val, vlen)));
}

class CouchAndForestTest : public ::testing::TestWithParam<std::string> {
};

class CouchKVStoreTest : public ::testing::TestWithParam<std::string> {
};

/* Test basic set / get of a document */
TEST_P(CouchAndForestTest, BasicTest) {
    std::string data_dir("/tmp/kvstore-test");
    CouchbaseDirectoryUtilities::rmrf(data_dir.c_str());

    KVStoreConfig config(1024, 4, data_dir, GetParam(), 0);
    auto kvstore = setup_kv_store(config);

    kvstore->begin();

    Item item("key", 3, 0, 0, "value", 5);
    WriteCallback wc;
    kvstore->set(item, wc);

    EXPECT_TRUE(kvstore->commit(nullptr));

    GetCallback gc;
    kvstore->get("key", 0, gc);
}

TEST(CouchKVStoreTest, CompressedTest) {
    std::string data_dir("/tmp/kvstore-test");
    CouchbaseDirectoryUtilities::rmrf(data_dir.c_str());

    KVStoreConfig config(1024, 4, data_dir, "couchdb", 0);
    auto kvstore = setup_kv_store(config);

    kvstore->begin();

    uint8_t datatype = PROTOCOL_BINARY_RAW_BYTES;
    WriteCallback wc;
    for (int i = 1; i <= 5; i++) {
        std::string key("key" + std::to_string(i));
        Item item(key.c_str(), key.length(),
                  0, 0, "value", 5, &datatype, 1, 0, i);
        kvstore->set(item, wc);
    }
    StatsCallback sc;
    kvstore->commit(&sc);

    std::shared_ptr<Callback<GetValue> > cb(new GetCallback(true));
    std::shared_ptr<Callback<CacheLookup> > cl(new CacheCallback(1, 5, 0));
    ScanContext* scanCtx;
    scanCtx = kvstore->initScanContext(cb, cl, 0, 1,
                                       DocumentFilter::ALL_ITEMS,
                                       ValueFilter::VALUES_COMPRESSED);

    ASSERT_NE(nullptr, scanCtx);
    EXPECT_EQ(scan_success, kvstore->scan(scanCtx));
    kvstore->destroyScanContext(scanCtx);
}

// Verify the stats returned from operations are accurate.
TEST(CouchKVStoreTest, StatsTest) {
    std::string data_dir("/tmp/kvstore-test");
    CouchbaseDirectoryUtilities::rmrf(data_dir.c_str());

    KVStoreConfig config(1024, 4, data_dir, "couchdb", 0);
    auto kvstore = setup_kv_store(config);

    // Perform a transaction with a single mutation (set) in it.
    kvstore->begin();
    const std::string key{"key"};
    const std::string value{"value"};
    Item item(key.c_str(), key.size(), 0, 0, value.c_str(), value.size());
    WriteCallback wc;
    kvstore->set(item, wc);

    StatsCallback sc;
    EXPECT_TRUE(kvstore->commit(&sc));
    // Check statistics are correct.
    std::map<std::string, std::string> stats;
    kvstore->addStats("", add_stat_callback, &stats);
    EXPECT_EQ("1", stats[":io_num_write"]);
    const size_t io_write_bytes = stoul(stats[":io_write_bytes"]);
    EXPECT_EQ(key.size() + value.size() + COUCHSTORE_METADATA_SIZE,
              io_write_bytes);

    // Hard to determine exactly how many bytes should have been written, but
    // expect non-zero, and least as many as the actual documents.
    const size_t io_total_write_bytes = stoul(stats[":io_total_write_bytes"]);
    EXPECT_GT(io_total_write_bytes, 0);
    EXPECT_GE(io_total_write_bytes, io_write_bytes);
}

// Test cases which run on both Couchstore and ForestDB
INSTANTIATE_TEST_CASE_P(CouchstoreAndForestDB,
                        CouchAndForestTest,
                        ::testing::Values("couchdb", "forestdb"));

static char allow_no_stats_env[] = "ALLOW_NO_STATS_UPDATE=yeah";

int main(int argc, char **argv) {
    ::testing::InitGoogleTest(&argc, argv);
    putenv(allow_no_stats_env);

    return RUN_ALL_TESTS();
}
<|endoftext|>