<commit_before>/*************************************************************************
 *
 *  OpenOffice.org - a multi-platform office productivity suite
 *
 *  $RCSfile: dtint.hxx,v $
 *
 *  $Revision: 1.16 $
 *
 *  last change: $Author: hr $ $Date: 2007-06-27 20:38:51 $
 *
 *  The Contents of this file are made available subject to
 *  the terms of GNU Lesser General Public License Version 2.1.
 *
 *
 *    GNU Lesser General Public License Version 2.1
 *    =============================================
 *    Copyright 2005 by Sun Microsystems, Inc.
 *    901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *    This library is free software; you can redistribute it and/or
 *    modify it under the terms of the GNU Lesser General Public
 *    License version 2.1, as published by the Free Software Foundation.
 *
 *    This library is distributed in the hope that it will be useful,
 *    but WITHOUT ANY WARRANTY; without even the implied warranty of
 *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *    Lesser General Public License for more details.
 *
 *    You should have received a copy of the GNU Lesser General Public
 *    License along with this library; if not, write to the Free Software
 *    Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *    MA  02111-1307  USA
 *
 ************************************************************************/
#ifndef _SV_DTINT_HXX
#define _SV_DTINT_HXX

#ifndef _LINK_HXX
#include <tools/link.hxx>
#endif
#ifndef _STRING_HXX
#include <tools/string.hxx>
#endif
#ifndef _TOOLS_COLOR_HXX
#include <tools/color.hxx>
#endif
#include <vcl/font.hxx>

class SalBitmap;
class SalDisplay;
class AllSettings;

#ifndef _XLIB_H_
// forwards from X
struct Display;
struct XEvent;
#define Atom UINT32
#define XLIB_Window UINT32
#endif

enum DtType {
    DtGeneric,
    DtCDE,
    DtMACOSX
};

class DtIntegrator
{
protected:
    DtType              meType;
    Display*            mpDisplay;
    SalDisplay*         mpSalDisplay;
    int                 mnSystemLookCommandProcess;

    DtIntegrator();

    static String           aHomeDir;

public:
    static DtIntegrator* CreateDtIntegrator();

    virtual ~DtIntegrator();

    // SystemLook
    virtual void GetSystemLook( AllSettings& rSettings );

    DtType          GetDtType() { return meType; }
    SalDisplay*     GetSalDisplay() { return mpSalDisplay; }
    Display*        GetDisplay() { return mpDisplay; }
};

#endif
<commit_msg>INTEGRATION: CWS changefileheader (1.16.248); FILE MERGED 2008/04/01 16:05:46 thb 1.16.248.2: #i85898# Stripping all external header guards 2008/03/28 15:45:14 rt 1.16.248.1: #i87441# Change license header to LPGL v3.<commit_after>/*************************************************************************
 *
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 *
 * Copyright 2008 by Sun Microsystems, Inc.
 *
 * OpenOffice.org - a multi-platform office productivity suite
 *
 * $RCSfile: dtint.hxx,v $
 * $Revision: 1.17 $
 *
 * This file is part of OpenOffice.org.
 *
 * OpenOffice.org is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Lesser General Public License version 3
 * only, as published by the Free Software Foundation.
 *
 * OpenOffice.org is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Lesser General Public License version 3 for more details
 * (a copy is included in the LICENSE file that accompanied this code).
 *
 * You should have received a copy of the GNU Lesser General Public License
 * version 3 along with OpenOffice.org.  If not, see
 * <http://www.openoffice.org/license.html>
 * for a copy of the LGPLv3 License.
 *
 ************************************************************************/
#ifndef _SV_DTINT_HXX
#define _SV_DTINT_HXX

#include <tools/link.hxx>
#include <tools/string.hxx>
#include <tools/color.hxx>
#include <vcl/font.hxx>

class SalBitmap;
class SalDisplay;
class AllSettings;

#ifndef _XLIB_H_
// forwards from X
struct Display;
struct XEvent;
#define Atom UINT32
#define XLIB_Window UINT32
#endif

enum DtType {
    DtGeneric,
    DtCDE,
    DtMACOSX
};

class DtIntegrator
{
protected:
    DtType              meType;
    Display*            mpDisplay;
    SalDisplay*         mpSalDisplay;
    int                 mnSystemLookCommandProcess;

    DtIntegrator();

    static String           aHomeDir;

public:
    static DtIntegrator* CreateDtIntegrator();

    virtual ~DtIntegrator();

    // SystemLook
    virtual void GetSystemLook( AllSettings& rSettings );

    DtType          GetDtType() { return meType; }
    SalDisplay*     GetSalDisplay() { return mpSalDisplay; }
    Display*        GetDisplay() { return mpDisplay; }
};

#endif
<|endoftext|>


<commit_before>/*
 *   O         ,-
 *   o    . -  '     ,-
 *     .        ` . ,
 *     (    ))     . (
 *      `-;_    . - `.`.
 *          `._'
 *
 * Copyright (c) 2007-2011 Markus Fisch <mf@markusfisch.de>
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/mit-license.php
 */
#include "Menu.h"
#include "WindowManager.h"

#include <X11/Xutil.h>
#include <unistd.h>
#include <stdlib.h>
#include <sstream>

using namespace PieDock;

/**
 * Initialize menu
 *
 * @param a - application
 */
Menu::Menu( Application *a ) :
	app( a ),
	selected( 0 ),
	menuItems( 0 )
{
}

/**
 * Update menu
 *
 * @param menuName - menu name
 */
bool Menu::update( std::string menuName )
{
	if( !(menuItems = app->getSettings()->getMenu( menuName )) )
		return false;

	// multiple windows per icon
	typedef std::map<Icon *, MenuItem *> IconToItem;
	IconToItem iconToItem;

	// one icon per window
	typedef std::map<Window, MenuItem *> WindowToItem;
	WindowToItem windowToItem;

	IconMap *iconMap = &app->getSettings()->getIconMap();

	// clear windows and make sure all items have valid icons
	{
		MenuItems::iterator si = menuItems->end();

		for( MenuItems::iterator i = menuItems->begin();
			i != menuItems->end();
			i++ )
		{
			Icon *icon;

			if( !(icon = (*i)->getIcon()) )
			{
				if( !(icon = iconMap->getIconByName( (*i)->getTitle() )) )
					icon = iconMap->getMissingIcon( (*i)->getTitle() );

				(*i)->setIcon( icon );
			}

			if( menuItems->oneIconPerWindow() )
			{
				windowToItem[(*i)->getNextWindow()] = (*i);

				if( *i == selected )
					si = i;
			}

			iconToItem[icon] = (*i);
			(*i)->clearWindows();
		}

		// move menu item to the top when one icon per window is used
		if( si != menuItems->end() )
		{
			menuItems->erase( si );
			menuItems->push_front( selected );
		}
	}

	// get filter
	std::string classFilter;

	if( menuItems->onlyFromActive() )
	{
		Window w = WindowManager::getActive( app->getDisplay() );
		XClassHint xch;

		if( w &&
			XGetClassHint( app->getDisplay(), w, &xch ) )
			classFilter = xch.res_class;
	}

	// assign windows to menu items; this is done by evaluating name, class
	// or title of the windows since you just can't trust window IDs over time
	{
		WindowManager::WindowList wl( app->getDisplay() );

		for( WindowManager::WindowList::iterator i = wl.begin();
			i != wl.end();
			i++ )
		{
			if( !WindowManager::isNormalWindow( app->getDisplay(), (*i) ) )
				continue;

			if( menuItems->oneIconPerWindow() )
			{
				WindowToItem::iterator w;

				if( (w = windowToItem.find( (*i) )) != windowToItem.end() )
				{
					if( menuItems->onlyFromActive() )
					{
						XClassHint xch;

						if( XGetClassHint( app->getDisplay(), (*i), &xch ) &&
							classFilter.compare( xch.res_class ) )
							continue;
					}

					(*w).second->addWindow( app->getDisplay(), (*i) );
					continue;
				}
			}

			XClassHint xch;

			if( !XGetClassHint( app->getDisplay(), (*i), &xch ) ||
				app->getSettings()->ignoreWindow( xch.res_name ) )
				continue;

			if( menuItems->onlyFromActive() &&
				classFilter.compare( xch.res_class ) )
				continue;

			Icon *icon;

			if( !(icon = iconMap->getIconByTitle(
					WindowManager::getTitle( app->getDisplay(), (*i) ) )) &&
				!(icon = iconMap->getIconByClass( xch.res_class )) &&
				!(icon = iconMap->getIconByName( xch.res_name )) )
				icon = iconMap->getMissingIcon( xch.res_name );

			if( menuItems->oneIconPerWindow() )
			{
				MenuItem *item = new MenuItem( icon );
				item->addWindow( app->getDisplay(), (*i) );

				menuItems->push_back( item );
				continue;
			}

			// find existing icon or create a new one
			{
				IconToItem::iterator m;

				if( (m = iconToItem.find( icon )) != iconToItem.end() )
					(*m).second->addWindow( app->getDisplay(), (*i) );
				else if( menuItems->includeWindows() )
				{
					MenuItem *item = new MenuItem( icon );
					item->addWindow( app->getDisplay(), (*i) );

					iconToItem[icon] = item;
					menuItems->push_back( item );
				}
			}
		}
	}

	// remove all menu items that have no windows and
	// are not sticky
	{
		MenuItems::iterator i = menuItems->begin();

		while( i != menuItems->end() )
			if( !(*i)->isSticky() &&
				!(*i)->hasWindows() )
			{
				delete (*i);
				i = menuItems->erase( i );
			}
			else
				++i;
	}

	// fill menu with dummy icons if there is a minimum number
	{
		int m = app->getSettings()->getMinimumNumber();

		if( m > 0 &&
			menuItems->size() < m )
		{
			for( m -= menuItems->size(); m--; )
				menuItems->push_back( new MenuItem(
					iconMap->getFillerIcon() ) );
		}
	}

	return true;
}

/**
 * Check if item points to another menu and if so, change to it
 *
 * @param a - action to execute (optional)
 */
bool Menu::change( Settings::Action a )
{
	if( !selected ||
		(
			a != Settings::Launch &&
			a != Settings::ShowNext &&
			a != Settings::ShowPrevious
		) )
		return false;

	std::string cmd = selected->getCommand();

	// check if this menu should launch another menu
	if( !cmd.compare( 0, 1, ":" ) )
	{
		update( cmd.substr( 1 ) );
		return true;
	}

	return false;
}

/**
 * Execute some action for the seleced icon
 *
 * @param a - action to execute (optional)
 */
void Menu::execute( Settings::Action a )
{
	if( !selected )
		return;

	// if there are no windows only Launch is allowed
	if( !selected->hasWindows() )
	{
		if( a != Settings::Launch &&
			a != Settings::ShowNext &&
			a != Settings::ShowPrevious )
			return;

		a = Settings::Launch;
	}

	switch( a )
	{
		case Settings::Launch:
			{
				std::string cmd = selected->getCommand();

				// substitute $WID with window ID
				{
					std::string::size_type p;

					if( (p = cmd.find( "$WID" )) != std::string::npos )
					{
						std::ostringstream oss;

						oss << cmd.substr( 0, p ) <<
							"0x" <<
							std::hex << getWindowBelowCursor() <<
							cmd.substr( p+4 );

						cmd = oss.str();
					}
				}

				run( cmd );
			}
			break;
		case Settings::ShowNext:
			WindowManager::activate(
				app->getDisplay(),
				selected->getNextWindow() );
			break;
		case Settings::ShowPrevious:
			WindowManager::activate(
				app->getDisplay(),
				selected->getPreviousWindow() );
			break;
		case Settings::Hide:
			WindowManager::iconify(
				app->getDisplay(),
				selected->getNextWindow() );
			break;
		case Settings::Close:
			WindowManager::close(
				app->getDisplay(),
				selected->getNextWindow() );
			break;
	}
}

/**
 * Return item title
 */
std::string Menu::getItemTitle() const
{
	if( selected )
	{
		if( !selected->isSticky() &&
			selected->hasWindows() )
		{
			std::string t = WindowManager::getTitle(
				app->getDisplay(),
				selected->getNextWindow() );

			selected->setTitle( t );

			return t;
		}

		return selected->getTitle();
	}

	return "";
};

/**
 * Run some command
 *
 * @param command - command to execute
 */
int Menu::run( std::string command ) const
{
	int pid = fork();

	if( pid < 0 )
		throw "fork failed";
	else if( pid )
		return pid;

	char *shell = getenv( "SHELL" );

	if( !shell )
		shell = const_cast<char *>( "/bin/sh" );

    setsid();
    execl( shell, shell, "-c", command.c_str(), NULL );

	throw "exec failed";

	// make compiler happy
	return 0;
}
<commit_msg>improved icon determination in one-icon-per-window menus<commit_after>/*
 *   O         ,-
 *   o    . -  '     ,-
 *     .        ` . ,
 *     (    ))     . (
 *      `-;_    . - `.`.
 *          `._'
 *
 * Copyright (c) 2007-2011 Markus Fisch <mf@markusfisch.de>
 *
 * Licensed under the MIT license:
 * http://www.opensource.org/licenses/mit-license.php
 */
#include "Menu.h"
#include "WindowManager.h"

#include <X11/Xutil.h>
#include <unistd.h>
#include <stdlib.h>
#include <sstream>

using namespace PieDock;

/**
 * Initialize menu
 *
 * @param a - application
 */
Menu::Menu( Application *a ) :
	app( a ),
	selected( 0 ),
	menuItems( 0 )
{
}

/**
 * Update menu
 *
 * @param menuName - menu name
 */
bool Menu::update( std::string menuName )
{
	if( !(menuItems = app->getSettings()->getMenu( menuName )) )
		return false;

	// multiple windows per icon
	typedef std::map<Icon *, MenuItem *> IconToItem;
	IconToItem iconToItem;

	// one icon per window
	typedef std::map<Window, MenuItem *> WindowToItem;
	WindowToItem windowToItem;

	IconMap *iconMap = &app->getSettings()->getIconMap();

	// clear windows and make sure all items have valid icons
	{
		MenuItems::iterator si = menuItems->end();

		for( MenuItems::iterator i = menuItems->begin();
			i != menuItems->end();
			i++ )
		{
			Icon *icon;

			if( !(icon = (*i)->getIcon()) )
			{
				if( !(icon = iconMap->getIconByName( (*i)->getTitle() )) )
					icon = iconMap->getMissingIcon( (*i)->getTitle() );

				(*i)->setIcon( icon );
			}

			if( menuItems->oneIconPerWindow() )
			{
				windowToItem[(*i)->getNextWindow()] = (*i);

				if( *i == selected )
					si = i;
			}

			iconToItem[icon] = (*i);
			(*i)->clearWindows();
		}

		// move menu item to the top when one icon per window is used
		if( si != menuItems->end() )
		{
			menuItems->erase( si );
			menuItems->push_front( selected );
		}
	}

	// get filter
	std::string classFilter;

	if( menuItems->onlyFromActive() )
	{
		Window w = WindowManager::getActive( app->getDisplay() );
		XClassHint xch;

		if( w &&
			XGetClassHint( app->getDisplay(), w, &xch ) )
			classFilter = xch.res_class;
	}

	// assign windows to menu items; this is done by evaluating name, class
	// and title of the windows since you just can't trust window IDs over time
	{
		WindowManager::WindowList wl( app->getDisplay() );

		for( WindowManager::WindowList::iterator i = wl.begin();
			i != wl.end();
			i++ )
		{
			if( !WindowManager::isNormalWindow( app->getDisplay(), (*i) ) )
				continue;

			if( menuItems->oneIconPerWindow() )
			{
				WindowToItem::iterator w;

				if( (w = windowToItem.find( (*i) )) != windowToItem.end() )
				{
					XClassHint xch;
					Icon *icon;

					if( !XGetClassHint( app->getDisplay(), (*i), &xch ) )
						continue;

					if( menuItems->onlyFromActive() &&
						classFilter.compare( xch.res_class ) )
						continue;

					// always get icon anew when reusing a window ID
					if( (icon = iconMap->getIcon(
							WindowManager::getTitle( app->getDisplay(), (*i) ),
							xch.res_class,
							xch.res_name ) ))
						(*w).second->setIcon( icon );

					(*w).second->addWindow( app->getDisplay(), (*i) );
					continue;
				}
			}

			XClassHint xch;

			if( !XGetClassHint( app->getDisplay(), (*i), &xch ) ||
				app->getSettings()->ignoreWindow( xch.res_name ) )
				continue;

			if( menuItems->onlyFromActive() &&
				classFilter.compare( xch.res_class ) )
				continue;

			Icon *icon = iconMap->getIcon(
				WindowManager::getTitle( app->getDisplay(), (*i) ),
				xch.res_class,
				xch.res_name );

			if( menuItems->oneIconPerWindow() )
			{
				MenuItem *item = new MenuItem( icon );
				item->addWindow( app->getDisplay(), (*i) );

				menuItems->push_back( item );
				continue;
			}

			// find existing icon or create a new one
			{
				IconToItem::iterator m;

				if( (m = iconToItem.find( icon )) != iconToItem.end() )
					(*m).second->addWindow( app->getDisplay(), (*i) );
				else if( menuItems->includeWindows() )
				{
					MenuItem *item = new MenuItem( icon );
					item->addWindow( app->getDisplay(), (*i) );

					iconToItem[icon] = item;
					menuItems->push_back( item );
				}
			}
		}
	}

	// remove all menu items that have no windows and
	// are not sticky
	{
		MenuItems::iterator i = menuItems->begin();

		while( i != menuItems->end() )
			if( !(*i)->isSticky() &&
				!(*i)->hasWindows() )
			{
				delete (*i);
				i = menuItems->erase( i );
			}
			else
				++i;
	}

	// fill menu with dummy icons if there is a minimum number
	{
		int m = app->getSettings()->getMinimumNumber();

		if( m > 0 &&
			menuItems->size() < m )
		{
			for( m -= menuItems->size(); m--; )
				menuItems->push_back( new MenuItem(
					iconMap->getFillerIcon() ) );
		}
	}

	return true;
}

/**
 * Check if item points to another menu and if so, change to it
 *
 * @param a - action to execute (optional)
 */
bool Menu::change( Settings::Action a )
{
	if( !selected ||
		(
			a != Settings::Launch &&
			a != Settings::ShowNext &&
			a != Settings::ShowPrevious
		) )
		return false;

	std::string cmd = selected->getCommand();

	// check if this menu should launch another menu
	if( !cmd.compare( 0, 1, ":" ) )
	{
		update( cmd.substr( 1 ) );
		return true;
	}

	return false;
}

/**
 * Execute some action for the seleced icon
 *
 * @param a - action to execute (optional)
 */
void Menu::execute( Settings::Action a )
{
	if( !selected )
		return;

	// if there are no windows only Launch is allowed
	if( !selected->hasWindows() )
	{
		if( a != Settings::Launch &&
			a != Settings::ShowNext &&
			a != Settings::ShowPrevious )
			return;

		a = Settings::Launch;
	}

	switch( a )
	{
		case Settings::Launch:
			{
				std::string cmd = selected->getCommand();

				// substitute $WID with window ID
				{
					std::string::size_type p;

					if( (p = cmd.find( "$WID" )) != std::string::npos )
					{
						std::ostringstream oss;

						oss << cmd.substr( 0, p ) <<
							"0x" <<
							std::hex << getWindowBelowCursor() <<
							cmd.substr( p+4 );

						cmd = oss.str();
					}
				}

				run( cmd );
			}
			break;
		case Settings::ShowNext:
			WindowManager::activate(
				app->getDisplay(),
				selected->getNextWindow() );
			break;
		case Settings::ShowPrevious:
			WindowManager::activate(
				app->getDisplay(),
				selected->getPreviousWindow() );
			break;
		case Settings::Hide:
			WindowManager::iconify(
				app->getDisplay(),
				selected->getNextWindow() );
			break;
		case Settings::Close:
			WindowManager::close(
				app->getDisplay(),
				selected->getNextWindow() );
			break;
	}
}

/**
 * Return item title
 */
std::string Menu::getItemTitle() const
{
	if( selected )
	{
		if( !selected->isSticky() &&
			selected->hasWindows() )
		{
			std::string t = WindowManager::getTitle(
				app->getDisplay(),
				selected->getNextWindow() );

			selected->setTitle( t );

			return t;
		}

		return selected->getTitle();
	}

	return "";
};

/**
 * Run some command
 *
 * @param command - command to execute
 */
int Menu::run( std::string command ) const
{
	int pid = fork();

	if( pid < 0 )
		throw "fork failed";
	else if( pid )
		return pid;

	char *shell = getenv( "SHELL" );

	if( !shell )
		shell = const_cast<char *>( "/bin/sh" );

    setsid();
    execl( shell, shell, "-c", command.c_str(), NULL );

	throw "exec failed";

	// make compiler happy
	return 0;
}
<|endoftext|>


<commit_before>// Copyright (C) Microsoft Corporation. All rights reserved.

#include "TestAppPch.h"
#include <thread>
#include <chrono>
#include <playfab/PlayFabClientApi.h>
#include <playfab/PlayFabEventsApi.h>
#include <playfab/PlayFabSettings.h>
#include <playfab/QoS/PlayFabQoSApi.h>
#include "PlayFabEventTest.h"
#include "TestContext.h"
#include "TestDataTypes.h"

using namespace PlayFab;
using namespace ClientModels;
using namespace EventsModels;

namespace PlayFabUnit
{
    /// QoS API
    void PlayFabEventTest::QosResultApi(TestContext& testContext)
    {
        QoS::PlayFabQoSApi api;

        auto result = api.GetQoSResult(5, 200);

        if (result.lastErrorCode == 0)
            testContext.Pass();
        else
        {
            std::string errorMessage = "Error Code:"; // Work around XBO C++/CX Platform::String^ error, which happens
            errorMessage += result.lastErrorCode;     // when trying to create a std::string from a string literal + int
            testContext.Fail(errorMessage);
        }
    }

    /// EVENTS API
    /// Test that sends heavyweight events as a whole batch.
    static EventContents CreateEventContents(const std::string& eventName, int i)
    {
        PlayFab::EventsModels::EventContents event;
        std::stringstream name;
        name << eventName << i;
        event.Name = name.str();
        event.EventNamespace = "com.playfab.events.default";
        event.Payload["PropA"] = "prop-value-a";
        event.Payload["PropB"] = "prop-value-b";
        return event;
    }
    void PlayFabEventTest::EventsApi(TestContext& testContext)
    {
        if (!PlayFabClientAPI::IsClientLoggedIn())
        {
            testContext.Skip("Earlier tests failed to log in");
            return;
        }

        EventsModels::WriteEventsRequest request;

        // send several events
        for (int i = 0; i < 2; i++)
        {
            request.Events.push_back(CreateEventContents("event_A_", i));
            request.Events.push_back(CreateEventContents("event_B_", i));
        }

        PlayFabEventsAPI::WriteEvents(request,
            Callback(&PlayFabEventTest::OnEventsApiSucceeded),
            Callback(&PlayFabEventTest::OnEventsApiFailed),
            &testContext);
    }
    void PlayFabEventTest::OnEventsApiSucceeded(const PlayFab::EventsModels::WriteEventsResponse&, void* customData)
    {
        TestContext* testContext = reinterpret_cast<TestContext*>(customData);
        testContext->Pass();
    }
    void PlayFabEventTest::OnEventsApiFailed(const PlayFab::PlayFabError& error, void* customData)
    {
        TestContext* testContext = reinterpret_cast<TestContext*>(customData);
        testContext->Fail(error.GenerateErrorReport());
    }

    /// EVENTS API
    /// Shared functions & data
    std::shared_ptr<TestContext*> PlayFabEventTest::eventTestContext;
    size_t PlayFabEventTest::eventBatchMax;
    int PlayFabEventTest::eventPassCount;
    int PlayFabEventTest::eventFailCount;
    std::string PlayFabEventTest::eventFailLog;

    void PlayFabEventTest::EmitEventCallback(std::shared_ptr<const PlayFab::IPlayFabEvent> event, std::shared_ptr<const PlayFab::IPlayFabEmitEventResponse> response)
    {
        auto pfEvent = std::dynamic_pointer_cast<const PlayFab::PlayFabEvent>(event);
        auto pfResponse = std::dynamic_pointer_cast<const PlayFab::PlayFabEmitEventResponse>(response);

        // Handle successful event delivery.
        if (PlayFab::PlayFabErrorCode::PlayFabErrorSuccess == pfResponse->playFabError->ErrorCode)
        {
            ++eventPassCount;
            eventFailLog += pfEvent->GetName() + " was sent successfully " +
                "in the batch #" + std::to_string(pfResponse->batchNumber) + " "
                "of " + std::to_string(pfResponse->batch->size()) + " events. "
                "HTTP code: " + std::to_string(pfResponse->playFabError->HttpCode) +
                ", app error code: " + std::to_string(pfResponse->playFabError->ErrorCode) + "\n";

            // Keep track of the highest batch number.
            eventBatchMax = (pfResponse->batchNumber > eventBatchMax) ? pfResponse->batchNumber : eventBatchMax;
        }
        // Handle failed event delivery.
        else
        {
            ++eventFailCount;
            eventFailLog += pfEvent->GetName() + " received an error back " +
                "in the batch #" + std::to_string(pfResponse->batchNumber) + " "
                "of " + std::to_string(pfResponse->batch->size()) + " events. "
                "HTTP code: " + std::to_string(pfResponse->playFabError->HttpCode) +
                ", app error code: " + std::to_string(pfResponse->playFabError->ErrorCode) +
                ", HTTP status: " + pfResponse->playFabError->HttpStatus +
                ", Message: " + pfResponse->playFabError->ErrorMessage +
                "\n";
        }

        // Complete the test once all events have been processed.
        const int eventCount = eventPassCount + eventFailCount;
        if (eventCount >= eventEmitCount)
        {
            if (eventBatchMax >= eventEmitCount)
                (*eventTestContext)->Fail("Events did not batch:\n" + eventFailLog);
            else if (eventFailCount > 0)
                (*eventTestContext)->Fail("Events failed delivery:\n" + eventFailLog);
            else
                (*eventTestContext)->Pass();
        }
    }
    void PlayFabEventTest::EmitEvents(PlayFab::PlayFabEventType eventType)
    {
        // Emit several events quickly.
        // They will be batched up according to pipeline's settings
        for (int i = 0; i < eventEmitCount; i++)
        {
            auto event = std::unique_ptr<PlayFab::PlayFabEvent>(new PlayFab::PlayFabEvent());

            // user can specify whether it's
            // - lightweight (goes to 1DS),
            // - heavyweight (goes to PlayFab's WriteEvents),
            // - or anything else
            event->eventType = eventType;
            std::stringstream name;
            name << "event_" << i;
            event->SetName(name.str());
            event->SetProperty("prop_A", 123);
            event->SetProperty("prop_B", "hello, world!");
            event->SetProperty("prop_C", true);

            (*eventApi)->EmitEvent(std::move(event), EmitEventCallback);
        }
    }

    /// EVENTS API
    /// PlayFab heavyweight events (emitted individually
    ///   and processed in a background thread using event pipeline (router, batching, etc))
    void PlayFabEventTest::HeavyweightEvents(TestContext& testContext)
    {
        eventTestContext = std::make_shared<TestContext*>(&testContext);

        // test custom event API (it uses event pipeline (router, batching, etc))
        eventApi = std::make_shared<PlayFabEventAPI*>(new PlayFabEventAPI()); // create Event API instance

        // adjust some pipeline settings
        auto pipeline = std::dynamic_pointer_cast<PlayFab::PlayFabEventPipeline>((*eventApi)->GetEventRouter()->GetPipelines().at(PlayFab::EventPipelineKey::PlayFab)); // get PF pipeline
        auto settings = pipeline->GetSettings(); // get pipeline's settings
        settings->maximalBatchWaitTime = 4; // incomplete batch expiration in seconds
        settings->maximalNumberOfItemsInBatch = 4; // number of events in a batch
        settings->maximalNumberOfBatchesInFlight = 3; // maximal number of batches processed simultaneously by a transport plugin before taking next events from the buffer

        EmitEvents(PlayFab::PlayFabEventType::Heavyweight);
    }

    /// EVENTS API
    /// OneDS lightweight events (emitted individually
    ///   and processed in a background thread using event pipeline (router, batching, etc))
    void PlayFabEventTest::LightweightEvents(TestContext& testContext)
    {
        eventTestContext = std::make_shared<TestContext*>(&testContext);

        // test custom event API (it uses event pipeline (router, batching, etc))
        eventApi = std::make_shared<PlayFabEventAPI*>(new PlayFabEventAPI()); // create Event API instance

        // adjust some pipeline settings
        auto pipeline = std::dynamic_pointer_cast<PlayFab::PlayFabEventPipeline>((*eventApi)->GetEventRouter()->GetPipelines().at(PlayFab::EventPipelineKey::OneDS)); // get OneDS pipeline
        auto settings = pipeline->GetSettings(); // get pipeline's settings
        settings->maximalBatchWaitTime = 2; // incomplete batch expiration in seconds
        settings->maximalNumberOfItemsInBatch = 3; // number of events in a batch
        settings->maximalNumberOfBatchesInFlight = 10; // maximal number of batches processed simultaneously by a transport plugin before taking next events from the buffer

        EmitEvents(PlayFab::PlayFabEventType::Lightweight);
    }

    /// EVENTS API
    /// OneDS Events API (lightweight events sent as a whole batch)
    void PlayFabEventTest::OneDSEventsApi(TestContext& testContext)
    {
        TelemetryIngestionConfigRequest configRequest;

        PlayFab::OneDSEventsAPI::GetTelemetryIngestionConfig(configRequest,
            Callback(&PlayFabEventTest::OnGetTelemetryIngestionConfig),
            Callback(&PlayFabEventTest::OnGetTelemetryIngestionConfigFail),
            &testContext);
    }
    void PlayFabEventTest::OnGetTelemetryIngestionConfig(const TelemetryIngestionConfigResponse& result, void* customData)
    {
        // create OneDS Events API instance
        PlayFab::OneDSEventsAPI api;
        api.SetCredentials("o:" + result.TenantId,
            result.IngestionKey,
            result.TelemetryJwtToken,
            result.TelemetryJwtHeaderKey,
            result.TelemetryJwtHeaderPrefix);

        // Prepare a batch of events
        PlayFab::EventsModels::WriteEventsRequest req;
        for (int j = 0; j < 5; j++)
        {
            for (int i = 0; i < 2; i++)
            {
                req.Events.push_back(CreateEventContents("event_AA_", i));
                req.Events.push_back(CreateEventContents("event_BB_", i));
            }
        }

        // Send the batch
        api.WriteTelemetryEvents(req,
            Callback(&PlayFabEventTest::OnOneDSWriteTelemetryEvents),
            Callback(&PlayFabEventTest::OnOneDSWriteTelemetryEventsFail),
            customData);
    }
    void PlayFabEventTest::OnGetTelemetryIngestionConfigFail(const PlayFabError& error, void* customData)
    {
        TestContext* testContext = reinterpret_cast<TestContext*>(customData);
        testContext->Fail("GetTelemetryIngestionConfig Failed : " + error.GenerateErrorReport());
    }
    void PlayFabEventTest::OnOneDSWriteTelemetryEvents(const WriteEventsResponse&, void* customData)
    {
        TestContext* testContext = reinterpret_cast<TestContext*>(customData);
        testContext->Pass();
    }
    void PlayFabEventTest::OnOneDSWriteTelemetryEventsFail(const PlayFabError& error, void* customData)
    {
        TestContext* testContext = reinterpret_cast<TestContext*>(customData);
        testContext->Fail("OneDS WriteTelemetryEvents Failed : " + error.GenerateErrorReport());
    }

    void PlayFabEventTest::AddTests()
    {
        AddTest("QosResultApi", &PlayFabEventTest::QosResultApi);
        AddTest("EventsApi", &PlayFabEventTest::EventsApi);
        AddTest("HeavyweightEvents", &PlayFabEventTest::HeavyweightEvents);
        AddTest("LightweightEvents", &PlayFabEventTest::LightweightEvents);
        AddTest("OneDSEventsApi", &PlayFabEventTest::OneDSEventsApi);
    }

    void PlayFabEventTest::ClassSetUp()
    {
        // Make sure PlayFab state is clean.
        PlayFabSettings::ForgetAllCredentials();

        // Log in to use event functions.
        LoginWithCustomIDRequest request;
        request.CustomId = PlayFabSettings::buildIdentifier;
        request.CreateAccount = true;

        loggedIn = false;
        bool loginComplete = false;
        PlayFabClientAPI::LoginWithCustomID(request,
            [&loginComplete](const LoginResult& /*result*/, void* customData)
            {
                *reinterpret_cast<bool*>(customData) = true;
                loginComplete = true;
            },
            [&loginComplete](const PlayFabError /*error*/, void* customData)
            {
                *reinterpret_cast<bool*>(customData) = false;
                loginComplete = true;
            },
            &loggedIn);

        // Sleep while waiting for log in to complete.
        while (!loginComplete)
        {
            std::this_thread::sleep_for(TimeValueMs(100));
        }
    }

    void PlayFabEventTest::SetUp(TestContext& testContext)
    {
        if (!loggedIn)
            testContext.Skip("Not logged in to PlayFab"); // Cannot run event tests if not logged in

        // Reset event test values.
        eventBatchMax = 0;
        eventPassCount = 0;
        eventFailCount = 0;
        eventFailLog = "";
    }

    void PlayFabEventTest::Tick(TestContext& /*testContext*/)
    {
        // No work needed, async tests will end themselves
    }

    void PlayFabEventTest::TearDown(TestContext& /*testContext*/)
    {
        eventTestContext = nullptr;
        eventApi = nullptr;
    }

    void PlayFabEventTest::ClassTearDown()
    {
        // Clean up any PlayFab state for next TestCase.
        PlayFabSettings::ForgetAllCredentials();
    }
}<commit_msg>Fix Win32 TestApp compile error (#437)<commit_after>// Copyright (C) Microsoft Corporation. All rights reserved.

#include "TestAppPch.h"
#include <thread>
#include <chrono>
#include <playfab/PlayFabClientApi.h>
#include <playfab/PlayFabEventsApi.h>
#include <playfab/PlayFabSettings.h>
#include <playfab/QoS/PlayFabQoSApi.h>
#include "PlayFabEventTest.h"
#include "TestContext.h"
#include "TestDataTypes.h"

using namespace PlayFab;
using namespace ClientModels;
using namespace EventsModels;

namespace PlayFabUnit
{
    /// QoS API
    void PlayFabEventTest::QosResultApi(TestContext& testContext)
    {
        QoS::PlayFabQoSApi api;

        auto result = api.GetQoSResult(5, 200);

        if (result.lastErrorCode == 0)
            testContext.Pass();
        else
            testContext.Fail("Error Code:" + std::to_string(result.lastErrorCode));
    }

    /// EVENTS API
    /// Test that sends heavyweight events as a whole batch.
    static EventContents CreateEventContents(const std::string& eventName, int i)
    {
        PlayFab::EventsModels::EventContents event;
        std::stringstream name;
        name << eventName << i;
        event.Name = name.str();
        event.EventNamespace = "com.playfab.events.default";
        event.Payload["PropA"] = "prop-value-a";
        event.Payload["PropB"] = "prop-value-b";
        return event;
    }
    void PlayFabEventTest::EventsApi(TestContext& testContext)
    {
        if (!PlayFabClientAPI::IsClientLoggedIn())
        {
            testContext.Skip("Earlier tests failed to log in");
            return;
        }

        EventsModels::WriteEventsRequest request;

        // send several events
        for (int i = 0; i < 2; i++)
        {
            request.Events.push_back(CreateEventContents("event_A_", i));
            request.Events.push_back(CreateEventContents("event_B_", i));
        }

        PlayFabEventsAPI::WriteEvents(request,
            Callback(&PlayFabEventTest::OnEventsApiSucceeded),
            Callback(&PlayFabEventTest::OnEventsApiFailed),
            &testContext);
    }
    void PlayFabEventTest::OnEventsApiSucceeded(const PlayFab::EventsModels::WriteEventsResponse&, void* customData)
    {
        TestContext* testContext = reinterpret_cast<TestContext*>(customData);
        testContext->Pass();
    }
    void PlayFabEventTest::OnEventsApiFailed(const PlayFab::PlayFabError& error, void* customData)
    {
        TestContext* testContext = reinterpret_cast<TestContext*>(customData);
        testContext->Fail(error.GenerateErrorReport());
    }

    /// EVENTS API
    /// Shared functions & data
    std::shared_ptr<TestContext*> PlayFabEventTest::eventTestContext;
    size_t PlayFabEventTest::eventBatchMax;
    int PlayFabEventTest::eventPassCount;
    int PlayFabEventTest::eventFailCount;
    std::string PlayFabEventTest::eventFailLog;

    void PlayFabEventTest::EmitEventCallback(std::shared_ptr<const PlayFab::IPlayFabEvent> event, std::shared_ptr<const PlayFab::IPlayFabEmitEventResponse> response)
    {
        auto pfEvent = std::dynamic_pointer_cast<const PlayFab::PlayFabEvent>(event);
        auto pfResponse = std::dynamic_pointer_cast<const PlayFab::PlayFabEmitEventResponse>(response);

        // Handle successful event delivery.
        if (PlayFab::PlayFabErrorCode::PlayFabErrorSuccess == pfResponse->playFabError->ErrorCode)
        {
            ++eventPassCount;
            eventFailLog += pfEvent->GetName() + " was sent successfully " +
                "in the batch #" + std::to_string(pfResponse->batchNumber) + " "
                "of " + std::to_string(pfResponse->batch->size()) + " events. "
                "HTTP code: " + std::to_string(pfResponse->playFabError->HttpCode) +
                ", app error code: " + std::to_string(pfResponse->playFabError->ErrorCode) + "\n";

            // Keep track of the highest batch number.
            eventBatchMax = (pfResponse->batchNumber > eventBatchMax) ? pfResponse->batchNumber : eventBatchMax;
        }
        // Handle failed event delivery.
        else
        {
            ++eventFailCount;
            eventFailLog += pfEvent->GetName() + " received an error back " +
                "in the batch #" + std::to_string(pfResponse->batchNumber) + " "
                "of " + std::to_string(pfResponse->batch->size()) + " events. "
                "HTTP code: " + std::to_string(pfResponse->playFabError->HttpCode) +
                ", app error code: " + std::to_string(pfResponse->playFabError->ErrorCode) +
                ", HTTP status: " + pfResponse->playFabError->HttpStatus +
                ", Message: " + pfResponse->playFabError->ErrorMessage +
                "\n";
        }

        // Complete the test once all events have been processed.
        const int eventCount = eventPassCount + eventFailCount;
        if (eventCount >= eventEmitCount)
        {
            if (eventBatchMax >= eventEmitCount)
                (*eventTestContext)->Fail("Events did not batch:\n" + eventFailLog);
            else if (eventFailCount > 0)
                (*eventTestContext)->Fail("Events failed delivery:\n" + eventFailLog);
            else
                (*eventTestContext)->Pass();
        }
    }
    void PlayFabEventTest::EmitEvents(PlayFab::PlayFabEventType eventType)
    {
        // Emit several events quickly.
        // They will be batched up according to pipeline's settings
        for (int i = 0; i < eventEmitCount; i++)
        {
            auto event = std::unique_ptr<PlayFab::PlayFabEvent>(new PlayFab::PlayFabEvent());

            // user can specify whether it's
            // - lightweight (goes to 1DS),
            // - heavyweight (goes to PlayFab's WriteEvents),
            // - or anything else
            event->eventType = eventType;
            std::stringstream name;
            name << "event_" << i;
            event->SetName(name.str());
            event->SetProperty("prop_A", 123);
            event->SetProperty("prop_B", "hello, world!");
            event->SetProperty("prop_C", true);

            (*eventApi)->EmitEvent(std::move(event), EmitEventCallback);
        }
    }

    /// EVENTS API
    /// PlayFab heavyweight events (emitted individually
    ///   and processed in a background thread using event pipeline (router, batching, etc))
    void PlayFabEventTest::HeavyweightEvents(TestContext& testContext)
    {
        eventTestContext = std::make_shared<TestContext*>(&testContext);

        // test custom event API (it uses event pipeline (router, batching, etc))
        eventApi = std::make_shared<PlayFabEventAPI*>(new PlayFabEventAPI()); // create Event API instance

        // adjust some pipeline settings
        auto pipeline = std::dynamic_pointer_cast<PlayFab::PlayFabEventPipeline>((*eventApi)->GetEventRouter()->GetPipelines().at(PlayFab::EventPipelineKey::PlayFab)); // get PF pipeline
        auto settings = pipeline->GetSettings(); // get pipeline's settings
        settings->maximalBatchWaitTime = 4; // incomplete batch expiration in seconds
        settings->maximalNumberOfItemsInBatch = 4; // number of events in a batch
        settings->maximalNumberOfBatchesInFlight = 3; // maximal number of batches processed simultaneously by a transport plugin before taking next events from the buffer

        EmitEvents(PlayFab::PlayFabEventType::Heavyweight);
    }

    /// EVENTS API
    /// OneDS lightweight events (emitted individually
    ///   and processed in a background thread using event pipeline (router, batching, etc))
    void PlayFabEventTest::LightweightEvents(TestContext& testContext)
    {
        eventTestContext = std::make_shared<TestContext*>(&testContext);

        // test custom event API (it uses event pipeline (router, batching, etc))
        eventApi = std::make_shared<PlayFabEventAPI*>(new PlayFabEventAPI()); // create Event API instance

        // adjust some pipeline settings
        auto pipeline = std::dynamic_pointer_cast<PlayFab::PlayFabEventPipeline>((*eventApi)->GetEventRouter()->GetPipelines().at(PlayFab::EventPipelineKey::OneDS)); // get OneDS pipeline
        auto settings = pipeline->GetSettings(); // get pipeline's settings
        settings->maximalBatchWaitTime = 2; // incomplete batch expiration in seconds
        settings->maximalNumberOfItemsInBatch = 3; // number of events in a batch
        settings->maximalNumberOfBatchesInFlight = 10; // maximal number of batches processed simultaneously by a transport plugin before taking next events from the buffer

        EmitEvents(PlayFab::PlayFabEventType::Lightweight);
    }

    /// EVENTS API
    /// OneDS Events API (lightweight events sent as a whole batch)
    void PlayFabEventTest::OneDSEventsApi(TestContext& testContext)
    {
        TelemetryIngestionConfigRequest configRequest;

        PlayFab::OneDSEventsAPI::GetTelemetryIngestionConfig(configRequest,
            Callback(&PlayFabEventTest::OnGetTelemetryIngestionConfig),
            Callback(&PlayFabEventTest::OnGetTelemetryIngestionConfigFail),
            &testContext);
    }
    void PlayFabEventTest::OnGetTelemetryIngestionConfig(const TelemetryIngestionConfigResponse& result, void* customData)
    {
        // create OneDS Events API instance
        PlayFab::OneDSEventsAPI api;
        api.SetCredentials("o:" + result.TenantId,
            result.IngestionKey,
            result.TelemetryJwtToken,
            result.TelemetryJwtHeaderKey,
            result.TelemetryJwtHeaderPrefix);

        // Prepare a batch of events
        PlayFab::EventsModels::WriteEventsRequest req;
        for (int j = 0; j < 5; j++)
        {
            for (int i = 0; i < 2; i++)
            {
                req.Events.push_back(CreateEventContents("event_AA_", i));
                req.Events.push_back(CreateEventContents("event_BB_", i));
            }
        }

        // Send the batch
        api.WriteTelemetryEvents(req,
            Callback(&PlayFabEventTest::OnOneDSWriteTelemetryEvents),
            Callback(&PlayFabEventTest::OnOneDSWriteTelemetryEventsFail),
            customData);
    }
    void PlayFabEventTest::OnGetTelemetryIngestionConfigFail(const PlayFabError& error, void* customData)
    {
        TestContext* testContext = reinterpret_cast<TestContext*>(customData);
        testContext->Fail("GetTelemetryIngestionConfig Failed : " + error.GenerateErrorReport());
    }
    void PlayFabEventTest::OnOneDSWriteTelemetryEvents(const WriteEventsResponse&, void* customData)
    {
        TestContext* testContext = reinterpret_cast<TestContext*>(customData);
        testContext->Pass();
    }
    void PlayFabEventTest::OnOneDSWriteTelemetryEventsFail(const PlayFabError& error, void* customData)
    {
        TestContext* testContext = reinterpret_cast<TestContext*>(customData);
        testContext->Fail("OneDS WriteTelemetryEvents Failed : " + error.GenerateErrorReport());
    }

    void PlayFabEventTest::AddTests()
    {
        AddTest("QosResultApi", &PlayFabEventTest::QosResultApi);
        AddTest("EventsApi", &PlayFabEventTest::EventsApi);
        AddTest("HeavyweightEvents", &PlayFabEventTest::HeavyweightEvents);
        AddTest("LightweightEvents", &PlayFabEventTest::LightweightEvents);
        AddTest("OneDSEventsApi", &PlayFabEventTest::OneDSEventsApi);
    }

    void PlayFabEventTest::ClassSetUp()
    {
        // Make sure PlayFab state is clean.
        PlayFabSettings::ForgetAllCredentials();

        // Log in to use event functions.
        LoginWithCustomIDRequest request;
        request.CustomId = PlayFabSettings::buildIdentifier;
        request.CreateAccount = true;

        loggedIn = false;
        bool loginComplete = false;
        PlayFabClientAPI::LoginWithCustomID(request,
            [&loginComplete](const LoginResult& /*result*/, void* customData)
            {
                *reinterpret_cast<bool*>(customData) = true;
                loginComplete = true;
            },
            [&loginComplete](const PlayFabError /*error*/, void* customData)
            {
                *reinterpret_cast<bool*>(customData) = false;
                loginComplete = true;
            },
            &loggedIn);

        // Sleep while waiting for log in to complete.
        while (!loginComplete)
        {
            std::this_thread::sleep_for(TimeValueMs(100));
        }
    }

    void PlayFabEventTest::SetUp(TestContext& testContext)
    {
        if (!loggedIn)
            testContext.Skip("Not logged in to PlayFab"); // Cannot run event tests if not logged in

        // Reset event test values.
        eventBatchMax = 0;
        eventPassCount = 0;
        eventFailCount = 0;
        eventFailLog = "";
    }

    void PlayFabEventTest::Tick(TestContext& /*testContext*/)
    {
        // No work needed, async tests will end themselves
    }

    void PlayFabEventTest::TearDown(TestContext& /*testContext*/)
    {
        eventTestContext = nullptr;
        eventApi = nullptr;
    }

    void PlayFabEventTest::ClassTearDown()
    {
        // Clean up any PlayFab state for next TestCase.
        PlayFabSettings::ForgetAllCredentials();
    }
}<|endoftext|>


<commit_before>// This file is part of MLDB. Copyright 2015 Datacratic. All rights reserved.

/** http_streambuf.cc
    Jeremy Barnes, 26 November 2014
    Copyright (c) 2014 Datacratic Inc.  All rights reserved.

*/

#include <atomic>
#include <boost/iostreams/stream_buffer.hpp>
#include "mldb/http/http_rest_proxy.h"
#include "mldb/jml/utils/ring_buffer.h"
#include "mldb/vfs/filter_streams_registry.h"
#include "mldb/vfs/fs_utils.h"
#include "mldb/http/http_exception.h"
#include "mldb/types/basic_value_descriptions.h"
#include <chrono>
#include <future>

using namespace std;

namespace MLDB {

static FsObjectInfo
convertHeaderToInfo(const HttpHeader & header)
{
    FsObjectInfo result;

    if (header.responseCode() == 200) {
        result.exists = true;
        result.etag = header.tryGetHeader("etag");
        result.size = header.contentLength;
        string lastModified = header.tryGetHeader("last-modified");
        if (!lastModified.empty()) {
            static const char format[] = "%a, %d %b %Y %H:%M:%S %Z"; // rfc 1123
            struct tm tm;
            bzero(&tm, sizeof(tm));
            if (strptime(lastModified.c_str(), format, &tm)) {
                result.lastModified = Date(1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
                                           tm.tm_hour, tm.tm_min, tm.tm_sec);
            }
        }

        return result;
    }

    if (header.responseCode() >= 400 && header.responseCode() < 500) {
        result.exists = false;
        return result;
    }

    throw HttpReturnException(header.responseCode(),
                              "Unable to convert unknown header code "
                              + to_string(header.responseCode()) +
                              " to object info",
                              "code", header.responseCode());
}

struct HttpStreamingDownloadSource {

    /** Create a streaming download source.

        For options, the following is accepted:
        http-set-cookie: sets the given header in the request to the given value.
    */
    HttpStreamingDownloadSource(const std::string & urlStr,
                                const std::map<std::string, std::string> & options)
    {
        impl.reset(new Impl(urlStr, options));
        impl->start();
    }

    ~HttpStreamingDownloadSource()
    {
    }

    /** Wait for the HTTP header to be available from the connection, and
        return it.
    */
    HttpHeader getHeader() const
    {
        auto future = impl->headerPromise.get_future();
        return future.get();
    }

    typedef char char_type;
    struct category
        : //input_seekable,
        boost::iostreams::input,
        boost::iostreams::device_tag,
        boost::iostreams::closable_tag
    { };

    struct Impl {
        Impl(const std::string & urlStr,
             const std::map<std::string, std::string> & options)
            : proxy(urlStr), urlStr(urlStr), shutdown(false), dataQueue(100),
              eof(false), currentDone(0), headerSet(false)
        {
            for (auto & o: options) {
                if (o.first == "http-set-cookie")
                    proxy.setCookie(o.second);
                else if (o.first.find("http-") == 0)
                    throw MLDB::Exception("Unknown HTTP stream parameter " + o.first + " = " + o.second);
            }

            reset();
        }

        ~Impl()
        {
            stop();
        }

        HttpRestProxy proxy;
        std::string urlStr;

        atomic<bool> shutdown;
        exception_ptr lastExc;

        /* Data queue */
        ML::RingBufferSRMW<string> dataQueue;
        atomic<bool> eof;

        std::string current;
        size_t currentDone;

        vector<std::thread> threads; /* thread pool */

        std::atomic<bool> headerSet;
        std::promise<HttpHeader> headerPromise;

        /* cleanup all the variables that are used during reading, the
           "static" ones are left untouched */
        void reset()
        {
            shutdown = false;
            current = "";
            currentDone = 0;
            threads.clear();
        }

        void start()
        {
            threads.emplace_back(&Impl::runThread, this);
        }

        void stop()
        {
            shutdown = true;

            while (!dataQueue.tryPush("")) {
                string item;
                dataQueue.tryPop(item, 0.001);
            }

            for (thread & th: threads) {
                th.join();
            }

            threads.clear();

            if (!headerSet) {
                if (lastExc)
                    headerPromise.set_exception(lastExc);
                else headerPromise.set_value(HttpHeader());
            }
        }

        /* reader thread */
        std::streamsize read(char_type* s, std::streamsize n)
        {
            if (lastExc) {
                rethrow_exception(lastExc);
            }

            if (eof)
                return -1;

            if (currentDone == current.size()) {
                // Get some more data
                current = dataQueue.pop();
                currentDone = 0;

                if (current.empty()) {
                    if (lastExc) rethrow_exception(lastExc);
                    eof = true;
                    return -1;  // shutdown or empty
                }
            }

            if (lastExc) {
                rethrow_exception(lastExc);
            }

            size_t toDo = min<size_t>(current.size() - currentDone, n);
            const char_type * start = current.c_str() + currentDone;
            std::copy(start, start + toDo, s);

            currentDone += toDo;

            return toDo;
        }

        void runThread()
        {
            try {
                int errorCode =-1;
                std::string errorBody;
                bool error = false;
                auto onData = [&] (const std::string & data)
                    {
                        if (error) {
                            errorBody = data;
                            return false;
                        }
                        if (shutdown)
                            return false;
                        while (!shutdown && !dataQueue.tryPush(data)) {
                            std::this_thread::sleep_for(std::chrono::milliseconds(1));
                        }
                        return !shutdown;
                    };

                auto isRedirect = [](const HttpHeader & header)
                    {
                        return header.responseCode() >= 300
                        && header.responseCode() < 400;
                    };

                auto onHeader = [&] (const HttpHeader & header)
                    {
                        // Don't set the promise on a 3xx... it's a redirect
                        // and we will get the correct header later on
                        if (!isRedirect(header)) {
                            if (headerSet)
                                throw std::logic_error("set header twice");

                            if (!headerSet.exchange(true)) {
                                this->headerPromise.set_value(header);
                            }
                        }

                        if (shutdown)
                            return false;

                        //cerr << "got header " << header << endl;
                        errorCode = header.responseCode();

                        if (header.responseCode() != 200 && !isRedirect(header))
                            error = true;

                        return !shutdown;
                    };

                auto resp = proxy.get("", {}, {}, -1 /* timeout */,
                                      false /* exceptions */,
                                      onData, onHeader,
                                      true /* follow redirect */);

                if (shutdown)
                    return;

                if (resp.code() != 200) {
                    cerr << "resp.errorCode_ = " << resp.errorCode() << endl;
                    cerr << "resp.errorMessage = " << resp.errorMessage() << endl;
                    throw MLDB::Exception("HTTP code %d reading %s\n\n%s",
                }

                dataQueue.push("");

            } catch (const std::exception & exc) {
                lastExc = std::current_exception();
                dataQueue.tryPush("");
                if (!headerSet.exchange(true)) {
                    headerPromise.set_exception(lastExc);
                }
            }
        }

    };

    std::shared_ptr<Impl> impl;

    std::streamsize read(char_type* s, std::streamsize n)
    {
        return impl->read(s, n);
    }

    bool is_open() const
    {
        return !!impl;
    }

    void close()
    {
        impl.reset();
    }
};

std::pair<std::unique_ptr<std::streambuf>, FsObjectInfo>
makeHttpStreamingDownload(const std::string & uri,
                          const std::map<std::string, std::string> & options)
{
    std::unique_ptr<std::streambuf> result;
    HttpStreamingDownloadSource source(uri, options);
    const HttpHeader & header = source.getHeader();
    result.reset(new boost::iostreams::stream_buffer<HttpStreamingDownloadSource>
                 (source, 131072));
    return { std::move(result), convertHeaderToInfo(header) };
}

struct HttpUrlFsHandler: UrlFsHandler {
    HttpRestProxy proxy;

    virtual FsObjectInfo getInfo(const Url & url) const
    {
        auto info = tryGetInfo(url);
        if (!info)
            throw MLDB::Exception("Couldn't get URI info for " + url.toString());
        return info;
    }

    virtual FsObjectInfo tryGetInfo(const Url & url) const
    {
        HttpHeader header;
        FsObjectInfo result;
        HttpRestProxy::Response resp;
        bool didGetHeader = false;

        for (unsigned attempt = 0;  attempt < 5;  ++attempt) {

            if (attempt != 0)
                std::this_thread::sleep_for(std::chrono::milliseconds(100 * attempt + random() % 100));
            didGetHeader = false;

            auto onHeader = [&] (const HttpHeader & gotHeader)
                {
                    header = gotHeader;
                    didGetHeader = true;

                    // Return false to make CURL stop after the header
                    //return false;
                    return true;
                };

            resp = proxy.perform("HEAD", url.toDecodedString(),
                                 HttpRestProxy::Content(),
                                 {}, {}, 1.0, false, nullptr, onHeader,
                                 true /* follow redirects */);

            if (!didGetHeader && resp.errorCode() != 0) {
                cerr << "error retrieving HEAD (retry) " << url.toString() << ": "
                     << resp.errorMessage() << endl;
                continue;  // didn't get header; retry
            }

#if 0
            cerr << "header = " << header << endl;
            cerr << "resp = " << resp << endl;
            cerr << "resp.responseCode = " << resp.code_ << endl;
            cerr << "resp.errorCode = " << resp.errorCode() << endl;
            cerr << "resp.errorMessage = " << resp.errorMessage() << endl;
            cerr << "header.responseCode() = " << header.responseCode() << endl;
#endif

            if (header.responseCode() >= 200 && header.responseCode() < 500) {
                return convertHeaderToInfo(header);
            }

            if (header.responseCode() >= 500 && header.responseCode() < 600) {
                continue;
            }

            cerr << "don't know what to do with response code "
                 << header.responseCode()
                 << " from HEAD" << endl;
        }

        throw MLDB::Exception("Couldn't reach server to determine HEAD of '"
                            + url.toString() + "': HTTP code "
                            + (didGetHeader ? to_string(header.responseCode()) : string("(unknown)"))
                            + " " + resp.errorMessage());

        //if (resp.hasHeader("content-type"))
        //    result.contentType = resp.getHeader("content-type");

        //cerr << "result = " << result.lastModified << endl;

        return result;
    }

    virtual size_t getSize(const Url & url) const
    {
        return getInfo(url).size;
    }

    virtual std::string getEtag(const Url & url) const
    {
        return getInfo(url).etag;
    }

    virtual void makeDirectory(const Url & url) const
    {
        // no-op
    }

    virtual bool erase(const Url & url, bool throwException) const
    {
        throw MLDB::Exception("Http URIs don't support DELETE");
    }

    /** For each object under the given prefix (object or subdirectory),
        call the given callback.
    */
    virtual bool forEach(const Url & prefix,
                         const OnUriObject & onObject,
                         const OnUriSubdir & onSubdir,
                         const std::string & delimiter,
                         const std::string & startAt) const
    {
        throw MLDB::Exception("Http URIs don't support listing");
    }
};

/** Register Http with the filter streams API so that a filter_stream can be
    used to treat an Http object as a simple stream.
*/
struct RegisterHttpHandler {
    static UriHandler
    getHttpHandler(const std::string & scheme,
                   const std::string & resource,
                   std::ios_base::open_mode mode,
                   const std::map<std::string, std::string> & options,
                   const OnUriHandlerException & onException)
    {
        string::size_type pos = resource.find('/');
        if (pos == string::npos)
            throw MLDB::Exception("unable to find http bucket name in resource "
                                + resource);
        string bucket(resource, 0, pos);

        if (mode == ios::in) {
            std::pair<std::unique_ptr<std::streambuf>, FsObjectInfo> sb_info
                = makeHttpStreamingDownload(scheme+"://"+resource, options);
            std::shared_ptr<std::streambuf> buf(sb_info.first.release());
            return UriHandler(buf.get(), buf, sb_info.second);
        }
        else if (mode == ios::out) {
            throw MLDB::Exception("Can't currently upload files via HTTP/HTTPs");
        }
        else throw MLDB::Exception("no way to create http handler for non in/out");
    }

    RegisterHttpHandler()
    {
        registerUriHandler("http", getHttpHandler);
        registerUriHandler("https", getHttpHandler);

        registerUrlFsHandler("http", new HttpUrlFsHandler());
        registerUrlFsHandler("https", new HttpUrlFsHandler());
    }

} registerHttpHandler;

} // namespace MLDB
<commit_msg>Fixup for http_streambuf fixes<commit_after>// This file is part of MLDB. Copyright 2015 Datacratic. All rights reserved.

/** http_streambuf.cc
    Jeremy Barnes, 26 November 2014
    Copyright (c) 2014 Datacratic Inc.  All rights reserved.

*/

#include <atomic>
#include <boost/iostreams/stream_buffer.hpp>
#include "mldb/http/http_rest_proxy.h"
#include "mldb/jml/utils/ring_buffer.h"
#include "mldb/vfs/filter_streams_registry.h"
#include "mldb/vfs/fs_utils.h"
#include "mldb/http/http_exception.h"
#include "mldb/types/basic_value_descriptions.h"
#include <chrono>
#include <future>

using namespace std;

namespace MLDB {

static FsObjectInfo
convertHeaderToInfo(const HttpHeader & header)
{
    FsObjectInfo result;

    if (header.responseCode() == 200) {
        result.exists = true;
        result.etag = header.tryGetHeader("etag");
        result.size = header.contentLength;
        string lastModified = header.tryGetHeader("last-modified");
        if (!lastModified.empty()) {
            static const char format[] = "%a, %d %b %Y %H:%M:%S %Z"; // rfc 1123
            struct tm tm;
            bzero(&tm, sizeof(tm));
            if (strptime(lastModified.c_str(), format, &tm)) {
                result.lastModified = Date(1900 + tm.tm_year, tm.tm_mon + 1, tm.tm_mday,
                                           tm.tm_hour, tm.tm_min, tm.tm_sec);
            }
        }

        return result;
    }

    if (header.responseCode() >= 400 && header.responseCode() < 500) {
        result.exists = false;
        return result;
    }

    throw HttpReturnException(header.responseCode(),
                              "Unable to convert unknown header code "
                              + to_string(header.responseCode()) +
                              " to object info",
                              "code", header.responseCode());
}

struct HttpStreamingDownloadSource {

    /** Create a streaming download source.

        For options, the following is accepted:
        http-set-cookie: sets the given header in the request to the given value.
    */
    HttpStreamingDownloadSource(const std::string & urlStr,
                                const std::map<std::string, std::string> & options)
    {
        impl.reset(new Impl(urlStr, options));
        impl->start();
    }

    ~HttpStreamingDownloadSource()
    {
    }

    /** Wait for the HTTP header to be available from the connection, and
        return it.
    */
    HttpHeader getHeader() const
    {
        auto future = impl->headerPromise.get_future();
        return future.get();
    }

    typedef char char_type;
    struct category
        : //input_seekable,
        boost::iostreams::input,
        boost::iostreams::device_tag,
        boost::iostreams::closable_tag
    { };

    struct Impl {
        Impl(const std::string & urlStr,
             const std::map<std::string, std::string> & options)
            : proxy(urlStr), urlStr(urlStr), shutdown(false), dataQueue(100),
              eof(false), currentDone(0), headerSet(false)
        {
            for (auto & o: options) {
                if (o.first == "http-set-cookie")
                    proxy.setCookie(o.second);
                else if (o.first.find("http-") == 0)
                    throw MLDB::Exception("Unknown HTTP stream parameter " + o.first + " = " + o.second);
            }

            reset();
        }

        ~Impl()
        {
            stop();
        }

        HttpRestProxy proxy;
        std::string urlStr;

        atomic<bool> shutdown;
        exception_ptr lastExc;

        /* Data queue */
        ML::RingBufferSRMW<string> dataQueue;
        atomic<bool> eof;

        std::string current;
        size_t currentDone;

        vector<std::thread> threads; /* thread pool */

        std::atomic<bool> headerSet;
        std::promise<HttpHeader> headerPromise;

        /* cleanup all the variables that are used during reading, the
           "static" ones are left untouched */
        void reset()
        {
            shutdown = false;
            current = "";
            currentDone = 0;
            threads.clear();
        }

        void start()
        {
            threads.emplace_back(&Impl::runThread, this);
        }

        void stop()
        {
            shutdown = true;

            while (!dataQueue.tryPush("")) {
                string item;
                dataQueue.tryPop(item, 0.001);
            }

            for (thread & th: threads) {
                th.join();
            }

            threads.clear();

            if (!headerSet) {
                if (lastExc)
                    headerPromise.set_exception(lastExc);
                else headerPromise.set_value(HttpHeader());
            }
        }

        /* reader thread */
        std::streamsize read(char_type* s, std::streamsize n)
        {
            if (lastExc) {
                rethrow_exception(lastExc);
            }

            if (eof)
                return -1;

            if (currentDone == current.size()) {
                // Get some more data
                current = dataQueue.pop();
                currentDone = 0;

                if (current.empty()) {
                    if (lastExc) rethrow_exception(lastExc);
                    eof = true;
                    return -1;  // shutdown or empty
                }
            }

            if (lastExc) {
                rethrow_exception(lastExc);
            }

            size_t toDo = min<size_t>(current.size() - currentDone, n);
            const char_type * start = current.c_str() + currentDone;
            std::copy(start, start + toDo, s);

            currentDone += toDo;

            return toDo;
        }

        void runThread()
        {
            try {
                int errorCode =-1;
                std::string errorBody;
                bool error = false;
                auto onData = [&] (const std::string & data)
                    {
                        if (error) {
                            errorBody = data;
                            return false;
                        }
                        if (shutdown)
                            return false;
                        while (!shutdown && !dataQueue.tryPush(data)) {
                            std::this_thread::sleep_for(std::chrono::milliseconds(1));
                        }
                        return !shutdown;
                    };

                auto isRedirect = [](const HttpHeader & header)
                    {
                        return header.responseCode() >= 300
                        && header.responseCode() < 400;
                    };

                auto onHeader = [&] (const HttpHeader & header)
                    {
                        // Don't set the promise on a 3xx... it's a redirect
                        // and we will get the correct header later on
                        if (!isRedirect(header)) {
                            if (headerSet)
                                throw std::logic_error("set header twice");

                            if (!headerSet.exchange(true)) {
                                this->headerPromise.set_value(header);
                            }
                        }

                        if (shutdown)
                            return false;

                        //cerr << "got header " << header << endl;
                        errorCode = header.responseCode();

                        if (header.responseCode() != 200 && !isRedirect(header))
                            error = true;

                        return !shutdown;
                    };

                auto resp = proxy.get("", {}, {}, -1 /* timeout */,
                                      false /* exceptions */,
                                      onData, onHeader,
                                      true /* follow redirect */);

                if (shutdown)
                    return;

                if (resp.code() != 200) {
                    cerr << "resp.errorCode_ = " << resp.errorCode() << endl;
                    cerr << "resp.errorMessage = " << resp.errorMessage() << endl;
                    throw MLDB::Exception("HTTP code %d reading %s\n\n%s",
                                          resp.code(),
                                          urlStr.c_str(),
                                          resp.errorMessage().c_str());
                }

                dataQueue.push("");

            } catch (const std::exception & exc) {
                lastExc = std::current_exception();
                dataQueue.tryPush("");
                if (!headerSet.exchange(true)) {
                    headerPromise.set_exception(lastExc);
                }
            }
        }

    };

    std::shared_ptr<Impl> impl;

    std::streamsize read(char_type* s, std::streamsize n)
    {
        return impl->read(s, n);
    }

    bool is_open() const
    {
        return !!impl;
    }

    void close()
    {
        impl.reset();
    }
};

std::pair<std::unique_ptr<std::streambuf>, FsObjectInfo>
makeHttpStreamingDownload(const std::string & uri,
                          const std::map<std::string, std::string> & options)
{
    std::unique_ptr<std::streambuf> result;
    HttpStreamingDownloadSource source(uri, options);
    const HttpHeader & header = source.getHeader();
    result.reset(new boost::iostreams::stream_buffer<HttpStreamingDownloadSource>
                 (source, 131072));
    return { std::move(result), convertHeaderToInfo(header) };
}

struct HttpUrlFsHandler: UrlFsHandler {
    HttpRestProxy proxy;

    virtual FsObjectInfo getInfo(const Url & url) const
    {
        auto info = tryGetInfo(url);
        if (!info)
            throw MLDB::Exception("Couldn't get URI info for " + url.toString());
        return info;
    }

    virtual FsObjectInfo tryGetInfo(const Url & url) const
    {
        HttpHeader header;
        FsObjectInfo result;
        HttpRestProxy::Response resp;
        bool didGetHeader = false;

        for (unsigned attempt = 0;  attempt < 5;  ++attempt) {

            if (attempt != 0)
                std::this_thread::sleep_for(std::chrono::milliseconds(100 * attempt + random() % 100));
            didGetHeader = false;

            auto onHeader = [&] (const HttpHeader & gotHeader)
                {
                    header = gotHeader;
                    didGetHeader = true;

                    // Return false to make CURL stop after the header
                    //return false;
                    return true;
                };

            resp = proxy.perform("HEAD", url.toDecodedString(),
                                 HttpRestProxy::Content(),
                                 {}, {}, 1.0, false, nullptr, onHeader,
                                 true /* follow redirects */);

            if (!didGetHeader && resp.errorCode() != 0) {
                cerr << "error retrieving HEAD (retry) " << url.toString() << ": "
                     << resp.errorMessage() << endl;
                continue;  // didn't get header; retry
            }

#if 0
            cerr << "header = " << header << endl;
            cerr << "resp = " << resp << endl;
            cerr << "resp.responseCode = " << resp.code_ << endl;
            cerr << "resp.errorCode = " << resp.errorCode() << endl;
            cerr << "resp.errorMessage = " << resp.errorMessage() << endl;
            cerr << "header.responseCode() = " << header.responseCode() << endl;
#endif

            if (header.responseCode() >= 200 && header.responseCode() < 500) {
                return convertHeaderToInfo(header);
            }

            if (header.responseCode() >= 500 && header.responseCode() < 600) {
                continue;
            }

            cerr << "don't know what to do with response code "
                 << header.responseCode()
                 << " from HEAD" << endl;
        }

        throw MLDB::Exception("Couldn't reach server to determine HEAD of '"
                            + url.toString() + "': HTTP code "
                            + (didGetHeader ? to_string(header.responseCode()) : string("(unknown)"))
                            + " " + resp.errorMessage());

        //if (resp.hasHeader("content-type"))
        //    result.contentType = resp.getHeader("content-type");

        //cerr << "result = " << result.lastModified << endl;

        return result;
    }

    virtual size_t getSize(const Url & url) const
    {
        return getInfo(url).size;
    }

    virtual std::string getEtag(const Url & url) const
    {
        return getInfo(url).etag;
    }

    virtual void makeDirectory(const Url & url) const
    {
        // no-op
    }

    virtual bool erase(const Url & url, bool throwException) const
    {
        throw MLDB::Exception("Http URIs don't support DELETE");
    }

    /** For each object under the given prefix (object or subdirectory),
        call the given callback.
    */
    virtual bool forEach(const Url & prefix,
                         const OnUriObject & onObject,
                         const OnUriSubdir & onSubdir,
                         const std::string & delimiter,
                         const std::string & startAt) const
    {
        throw MLDB::Exception("Http URIs don't support listing");
    }
};

/** Register Http with the filter streams API so that a filter_stream can be
    used to treat an Http object as a simple stream.
*/
struct RegisterHttpHandler {
    static UriHandler
    getHttpHandler(const std::string & scheme,
                   const std::string & resource,
                   std::ios_base::open_mode mode,
                   const std::map<std::string, std::string> & options,
                   const OnUriHandlerException & onException)
    {
        string::size_type pos = resource.find('/');
        if (pos == string::npos)
            throw MLDB::Exception("unable to find http bucket name in resource "
                                + resource);
        string bucket(resource, 0, pos);

        if (mode == ios::in) {
            std::pair<std::unique_ptr<std::streambuf>, FsObjectInfo> sb_info
                = makeHttpStreamingDownload(scheme+"://"+resource, options);
            std::shared_ptr<std::streambuf> buf(sb_info.first.release());
            return UriHandler(buf.get(), buf, sb_info.second);
        }
        else if (mode == ios::out) {
            throw MLDB::Exception("Can't currently upload files via HTTP/HTTPs");
        }
        else throw MLDB::Exception("no way to create http handler for non in/out");
    }

    RegisterHttpHandler()
    {
        registerUriHandler("http", getHttpHandler);
        registerUriHandler("https", getHttpHandler);

        registerUrlFsHandler("http", new HttpUrlFsHandler());
        registerUrlFsHandler("https", new HttpUrlFsHandler());
    }

} registerHttpHandler;

} // namespace MLDB
<|endoftext|>


<commit_before>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sync.h"
#include "util.h"

#include <stdio.h>
#include <set>

#ifdef DEBUG_LOCKCONTENTION
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
{
    LogPrintf("LOCKCONTENTION: %s\n", pszName);
    LogPrintf("Locker: %s:%d\n", pszFile, nLine);
}
#endif /* DEBUG_LOCKCONTENTION */

#ifdef DEBUG_LOCKORDER
//
// Early deadlock detection.
// Problem being solved:
//    Thread 1 locks  A, then B, then C
//    Thread 2 locks  D, then C, then A
//     --> may result in deadlock between the two threads, depending on when they run.
// Solution implemented here:
// Keep track of pairs of locks: (A before B), (A before C), etc.
// Complain if any thread tries to lock in a different order.
//

struct CLockLocation {
    CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
    {
        mutexName = pszName;
        sourceFile = pszFile;
        sourceLine = nLine;
        fTry = fTryIn;
    }

    std::string ToString() const
    {
        return mutexName + "  " + sourceFile + ":" + ::ToString(sourceLine) + (fTry ? " (TRY)" : "");
    }

private:
    bool fTry;
    std::string mutexName;
    std::string sourceFile;
    int sourceLine;
};

typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
typedef std::set<std::pair<void*, void*> > InvLockOrders;

struct LockData {
    // Very ugly hack: as the global constructs and destructors run single
    // threaded, we use this boolean to know whether LockData still exists,
    // as DeleteLock can get called by global CCriticalSection destructors
    // after LockData disappears.
    bool available;
    LockData() : available(true) {}
    ~LockData() { available = false; }

    LockOrders lockorders;
    InvLockOrders invlockorders;
    std::mutex dd_mutex;
} static lockdata;

static thread_local std::unique_ptr<LockStack> lockstack;

static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
    LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
    LogPrintf("Previous lock order was:\n");
    for (const std::pair<void*, CLockLocation> & i : s2) {
        if (i.first == mismatch.first) {
            LogPrintf(" (1)");
        }
        if (i.first == mismatch.second) {
            LogPrintf(" (2)");
        }
        LogPrintf(" %s\n", i.second.ToString());
    }
    LogPrintf("Current lock order is:\n");
    for (const std::pair<void*, CLockLocation> & i : s1) {
        if (i.first == mismatch.first) {
            LogPrintf(" (1)");
        }
        if (i.first == mismatch.second) {
            LogPrintf(" (2)");
        }
        LogPrintf(" %s\n", i.second.ToString());
    }
    assert(false);
}

static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
{
    if (!lockstack)
        lockstack.reset(new LockStack);

    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);

    lockstack->push_back(std::make_pair(c, locklocation));

    for (const std::pair<void*, CLockLocation> & i : (*lockstack)) {
        if (i.first == c)
            break;

        std::pair<void*, void*> p1 = std::make_pair(i.first, c);
        if (lockdata.lockorders.count(p1))
            continue;
        lockdata.lockorders[p1] = (*lockstack);

        std::pair<void*, void*> p2 = std::make_pair(c, i.first);
        lockdata.invlockorders.insert(p2);
        if (lockdata.lockorders.count(p2))
            potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
    }
}

static void pop_lock()
{
    (*lockstack).pop_back();
}

void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
    push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
}

void LeaveCritical()
{
    pop_lock();
}

std::string LocksHeld()
{
    std::string result;
    for (const std::pair<void*, CLockLocation> & i : *lockstack)
        result += i.second.ToString() + std::string("\n");
    return result;
}

void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
{
    for (const std::pair<void*, CLockLocation> & i : *lockstack)
        if (i.first == cs)
            return;
    fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld());
    abort();
}

void DeleteLock(void* cs)
{
    if (!lockdata.available) {
        // We're already shutting down.
        return;
    }
    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
    std::pair<void*, void*> item = std::make_pair(cs, (void*)0);
    LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
    while (it != lockdata.lockorders.end() && it->first.first == cs) {
        std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
        lockdata.invlockorders.erase(invitem);
        lockdata.lockorders.erase(it++);
    }
    InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
    while (invit != lockdata.invlockorders.end() && invit->first == cs) {
        std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
        lockdata.lockorders.erase(invinvitem);
        lockdata.invlockorders.erase(invit++);
    }
}

#endif /* DEBUG_LOCKORDER */
<commit_msg>add missing memory header that can break potential builds on some systems<commit_after>// Copyright (c) 2011-2016 The Bitcoin Core developers
// Distributed under the MIT software license, see the accompanying
// file COPYING or http://www.opensource.org/licenses/mit-license.php.

#include "sync.h"
#include "util.h"

#include <stdio.h>
#include <set>
#include <memory>

#ifdef DEBUG_LOCKCONTENTION
void PrintLockContention(const char* pszName, const char* pszFile, int nLine)
{
    LogPrintf("LOCKCONTENTION: %s\n", pszName);
    LogPrintf("Locker: %s:%d\n", pszFile, nLine);
}
#endif /* DEBUG_LOCKCONTENTION */

#ifdef DEBUG_LOCKORDER
//
// Early deadlock detection.
// Problem being solved:
//    Thread 1 locks  A, then B, then C
//    Thread 2 locks  D, then C, then A
//     --> may result in deadlock between the two threads, depending on when they run.
// Solution implemented here:
// Keep track of pairs of locks: (A before B), (A before C), etc.
// Complain if any thread tries to lock in a different order.
//

struct CLockLocation {
    CLockLocation(const char* pszName, const char* pszFile, int nLine, bool fTryIn)
    {
        mutexName = pszName;
        sourceFile = pszFile;
        sourceLine = nLine;
        fTry = fTryIn;
    }

    std::string ToString() const
    {
        return mutexName + "  " + sourceFile + ":" + ::ToString(sourceLine) + (fTry ? " (TRY)" : "");
    }

private:
    bool fTry;
    std::string mutexName;
    std::string sourceFile;
    int sourceLine;
};

typedef std::vector<std::pair<void*, CLockLocation> > LockStack;
typedef std::map<std::pair<void*, void*>, LockStack> LockOrders;
typedef std::set<std::pair<void*, void*> > InvLockOrders;

struct LockData {
    // Very ugly hack: as the global constructs and destructors run single
    // threaded, we use this boolean to know whether LockData still exists,
    // as DeleteLock can get called by global CCriticalSection destructors
    // after LockData disappears.
    bool available;
    LockData() : available(true) {}
    ~LockData() { available = false; }

    LockOrders lockorders;
    InvLockOrders invlockorders;
    std::mutex dd_mutex;
} static lockdata;

static thread_local std::unique_ptr<LockStack> lockstack;

static void potential_deadlock_detected(const std::pair<void*, void*>& mismatch, const LockStack& s1, const LockStack& s2)
{
    LogPrintf("POTENTIAL DEADLOCK DETECTED\n");
    LogPrintf("Previous lock order was:\n");
    for (const std::pair<void*, CLockLocation> & i : s2) {
        if (i.first == mismatch.first) {
            LogPrintf(" (1)");
        }
        if (i.first == mismatch.second) {
            LogPrintf(" (2)");
        }
        LogPrintf(" %s\n", i.second.ToString());
    }
    LogPrintf("Current lock order is:\n");
    for (const std::pair<void*, CLockLocation> & i : s1) {
        if (i.first == mismatch.first) {
            LogPrintf(" (1)");
        }
        if (i.first == mismatch.second) {
            LogPrintf(" (2)");
        }
        LogPrintf(" %s\n", i.second.ToString());
    }
    assert(false);
}

static void push_lock(void* c, const CLockLocation& locklocation, bool fTry)
{
    if (!lockstack)
        lockstack.reset(new LockStack);

    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);

    lockstack->push_back(std::make_pair(c, locklocation));

    for (const std::pair<void*, CLockLocation> & i : (*lockstack)) {
        if (i.first == c)
            break;

        std::pair<void*, void*> p1 = std::make_pair(i.first, c);
        if (lockdata.lockorders.count(p1))
            continue;
        lockdata.lockorders[p1] = (*lockstack);

        std::pair<void*, void*> p2 = std::make_pair(c, i.first);
        lockdata.invlockorders.insert(p2);
        if (lockdata.lockorders.count(p2))
            potential_deadlock_detected(p1, lockdata.lockorders[p2], lockdata.lockorders[p1]);
    }
}

static void pop_lock()
{
    (*lockstack).pop_back();
}

void EnterCritical(const char* pszName, const char* pszFile, int nLine, void* cs, bool fTry)
{
    push_lock(cs, CLockLocation(pszName, pszFile, nLine, fTry), fTry);
}

void LeaveCritical()
{
    pop_lock();
}

std::string LocksHeld()
{
    std::string result;
    for (const std::pair<void*, CLockLocation> & i : *lockstack)
        result += i.second.ToString() + std::string("\n");
    return result;
}

void AssertLockHeldInternal(const char* pszName, const char* pszFile, int nLine, void* cs)
{
    for (const std::pair<void*, CLockLocation> & i : *lockstack)
        if (i.first == cs)
            return;
    fprintf(stderr, "Assertion failed: lock %s not held in %s:%i; locks held:\n%s", pszName, pszFile, nLine, LocksHeld());
    abort();
}

void DeleteLock(void* cs)
{
    if (!lockdata.available) {
        // We're already shutting down.
        return;
    }
    std::lock_guard<std::mutex> lock(lockdata.dd_mutex);
    std::pair<void*, void*> item = std::make_pair(cs, (void*)0);
    LockOrders::iterator it = lockdata.lockorders.lower_bound(item);
    while (it != lockdata.lockorders.end() && it->first.first == cs) {
        std::pair<void*, void*> invitem = std::make_pair(it->first.second, it->first.first);
        lockdata.invlockorders.erase(invitem);
        lockdata.lockorders.erase(it++);
    }
    InvLockOrders::iterator invit = lockdata.invlockorders.lower_bound(item);
    while (invit != lockdata.invlockorders.end() && invit->first == cs) {
        std::pair<void*, void*> invinvitem = std::make_pair(invit->second, invit->first);
        lockdata.lockorders.erase(invinvitem);
        lockdata.invlockorders.erase(invit++);
    }
}

#endif /* DEBUG_LOCKORDER */
<|endoftext|>


<commit_before>// primes.cpp : Defines the entry point for the console application.
//

#include <stdio.h>

bool is_prime(int);

char key[1024];

int main(int argc, char* argv[])
{
	int print_threshold = 10000, threshold_interval = 10000;

	for (int i = 0; i < 300000; i++) {
		if (is_prime(i)) {
			if (i > print_threshold) {
				printf("%d\n", i);
				print_threshold += threshold_interval;
			}
		}
	}

//	printf("Press Enter to continue\n");
//	getchar();
	return 0;
}

bool is_prime(int n)
{
	for (int i = 2; i < n; ++i) {
		if (n % i == 0) {
			return false;
		}
	}
	return true;
}<commit_msg>changed tabs to spaces<commit_after>// primes.cpp : Defines the entry point for the console application.
//

#include <stdio.h>

bool is_prime(int);

char key[1024];

int main(int argc, char* argv[])
{
  int print_threshold = 10000, threshold_interval = 10000;

  for (int i = 0; i < 300000; i++) {
    if (is_prime(i)) {
      if (i > print_threshold) {
        printf("%d\n", i);
        print_threshold += threshold_interval;
      }
    }
  }

//  printf("Press Enter to continue\n");
//  getchar();
  return 0;
}

bool is_prime(int n)
{
  for (int i = 2; i < n; ++i) {
    if (n % i == 0) {
      return false;
    }
  }
  return true;
}<|endoftext|>


<commit_before>#include <ygo/deck/User.h>

#include <ygo/deck/DB.h>
#include <ygo/deck/DeckSet.h>

#include <mindbw/SQLite3.h>
#include <ygo/data/Serialize.h>

#include <cassert>
#include <stdexcept>

namespace ygo
{
namespace deck
{

User::User(std::string name, bool create) :
    mName(std::move(name))
{
    // check if the user already exists
    auto exists = false;
    std::string userid;
    mindbw::SQLite3 db(DB::get().path());
    db.select(mindbw::KeyList({"name","user_id"}),"users",
            mindbw::Equal("name",mName),
            [&](mindbw::DataMap data) {
                exists = true;
                userid = data["user_id"];
            });

    if (exists) {
        mID = userid;
    } else if (create) {
        mID = db.insert("users",mindbw::ValueList({mName}));
    } else {
        throw std::runtime_error("User " + mName + " does not exist");
    }
}

std::vector<DeckSet> User::deckSets() const
{
    // return all deck sets for a given user
    std::vector<std::string> deckids;
    assert(!DB::get().path().empty());
    mindbw::SQLite3 db(DB::get().path());
    db.select("deck_set_id","user_to_decks",
            mindbw::Equal("user_id",id()),
            [&](mindbw::DataMap data) {
                deckids.push_back(data["deck_set_id"]);
            });

    // look up the deck set ids and convert them into objects
    std::vector<DeckSet> ret;
    for (auto&& i : deckids) {
        db.select(mindbw::All(),"deck_set",
                mindbw::Equal("deck_set_id",i),
                [&](mindbw::DataMap data) {
                    // extract the format
                    Format f(data::toFormat(data["format"]),
                        data["format_date"]);

                    // add a new DBDeckSet
                    ret.emplace_back(DeckSet{data["name"],*this,f});
                });
    }
    return ret;
}

void User::remove()
{
    // delete all the deck sets associated with this user
    auto sets = deckSets();
    for (auto&& s : sets) {
        s.remove();
    }

    // delete the user
    mindbw::SQLite3 db(DB::get().path());
    db.del("users",mindbw::Equal("user_id",mID));
}

}
}
<commit_msg>Android returns multiple deck_set_ids<commit_after>#include <ygo/deck/User.h>

#include <ygo/deck/DB.h>
#include <ygo/deck/DeckSet.h>

#include <mindbw/SQLite3.h>
#include <ygo/data/Serialize.h>

#include <cassert>
#include <stdexcept>

namespace ygo
{
namespace deck
{

User::User(std::string name, bool create) :
    mName(std::move(name))
{
    // check if the user already exists
    auto exists = false;
    std::string userid;
    mindbw::SQLite3 db(DB::get().path());
    db.select(mindbw::KeyList({"name","user_id"}),"users",
            mindbw::Equal("name",mName),
            [&](mindbw::DataMap data) {
                exists = true;
                userid = data["user_id"];
            });

    if (exists) {
        mID = userid;
    } else if (create) {
        mID = db.insert("users",mindbw::ValueList({mName}));
    } else {
        throw std::runtime_error("User " + mName + " does not exist");
    }
}

std::vector<DeckSet> User::deckSets() const
{
    // return all deck sets for a given user
    std::vector<std::string> deckids;
    assert(!DB::get().path().empty());
    mindbw::SQLite3 db(DB::get().path());
    db.select(mindbw::Unique("deck_set_id"),"user_to_decks",
            mindbw::Equal("user_id",id()),
            [&](mindbw::DataMap data) {
                deckids.push_back(data["deck_set_id"]);
            });

    // look up the deck set ids and convert them into objects
    std::vector<DeckSet> ret;
    for (auto&& i : deckids) {
        db.select(mindbw::All(),"deck_set",
                mindbw::Equal("deck_set_id",i),
                [&](mindbw::DataMap data) {
                    // extract the format
                    Format f(data::toFormat(data["format"]),
                        data["format_date"]);

                    // add a new DBDeckSet
                    ret.emplace_back(DeckSet{data["name"],*this,f});
                });
    }
    return ret;
}

void User::remove()
{
    // delete all the deck sets associated with this user
    auto sets = deckSets();
    for (auto&& s : sets) {
        s.remove();
    }

    // delete the user
    mindbw::SQLite3 db(DB::get().path());
    db.del("users",mindbw::Equal("user_id",mID));
}

}
}
<|endoftext|>