<commit_before>/* Copyright (C) 2005 MySQL AB

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifdef __GNUC__
#pragma implementation        // gcc: Class implementation
#endif

#include <mysql_priv.h>

#ifdef HAVE_BLACKHOLE_DB
#include "ha_blackhole.h"

const char **ha_blackhole::bas_ext() const
{
  static const char *ext[]= { NullS };
  return ext;
}

int ha_blackhole::open(const char *name, int mode, uint test_if_locked)
{
  DBUG_ENTER("ha_blackhole::open");
  thr_lock_init(&thr_lock);
  thr_lock_data_init(&thr_lock,&lock,NULL);
  DBUG_RETURN(0);
}

int ha_blackhole::close(void)
{
  DBUG_ENTER("ha_blackhole::close");
  thr_lock_delete(&thr_lock);
  DBUG_RETURN(0);
}

int ha_blackhole::create(const char *name, TABLE *table_arg,
                         HA_CREATE_INFO *create_info)
{
  DBUG_ENTER("ha_blackhole::create");
  DBUG_RETURN(0);
}

const char *ha_blackhole::index_type(uint key_number)
{
  DBUG_ENTER("ha_blackhole::index_type");
  DBUG_RETURN((table->key_info[key_number].flags & HA_FULLTEXT) ?
              "FULLTEXT" :
              (table->key_info[key_number].flags & HA_SPATIAL) ?
              "SPATIAL" :
              (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
              "RTREE" :
              "BTREE");
}

int ha_blackhole::write_row(byte * buf)
{
  DBUG_ENTER("ha_blackhole::write_row");
  DBUG_RETURN(0);
}

int ha_blackhole::rnd_init(bool scan)
{
  DBUG_ENTER("ha_blackhole::rnd_init");
  DBUG_RETURN(0);
}

int ha_blackhole::rnd_next(byte *buf)
{
  DBUG_ENTER("ha_blackhole::rnd_next");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::rnd_pos(byte * buf, byte *pos)
{
  DBUG_ENTER("ha_blackhole::rnd_pos");
  DBUG_ASSERT(0);
  DBUG_RETURN(0);
}

void ha_blackhole::position(const byte *record)
{
  DBUG_ENTER("ha_blackhole::position");
  DBUG_ASSERT(0);
  DBUG_VOID_RETURN;
}

void ha_blackhole::info(uint flag)
{
  DBUG_ENTER("ha_blackhole::info");

  records= 0;
  deleted= 0;
  errkey= 0;
  mean_rec_length= 0;
  data_file_length= 0;
  index_file_length= 0;
  max_data_file_length= 0;
  delete_length= 0;
  if (flag & HA_STATUS_AUTO)
    auto_increment_value= 1;
  DBUG_VOID_RETURN;
}

int ha_blackhole::external_lock(THD *thd, int lock_type)
{
  DBUG_ENTER("ha_blackhole::external_lock");
  DBUG_RETURN(0);
}

THR_LOCK_DATA **ha_blackhole::store_lock(THD *thd,
                                         THR_LOCK_DATA **to,
                                         enum thr_lock_type lock_type)
{
  *to++= &lock;

  return to;
}

int ha_blackhole::index_read(byte * buf, const byte * key,
                             uint key_len, enum ha_rkey_function find_flag)
{
  DBUG_ENTER("ha_blackhole::index_read");
  DBUG_RETURN(0);
}

int ha_blackhole::index_read_idx(byte * buf, uint idx, const byte * key,
                                 uint key_len, enum ha_rkey_function find_flag)
{
  DBUG_ENTER("ha_blackhole::index_read_idx");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::index_read_last(byte * buf, const byte * key, uint key_len)
{
  DBUG_ENTER("ha_blackhole::index_read_last");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::index_next(byte * buf)
{
  DBUG_ENTER("ha_blackhole::index_next");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::index_prev(byte * buf)
{
  DBUG_ENTER("ha_blackhole::index_prev");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::index_first(byte * buf)
{
  DBUG_ENTER("ha_blackhole::index_first");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::index_last(byte * buf)
{
  DBUG_ENTER("ha_blackhole::index_last");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

#endif /* HAVE_BLACKHOLE_DB */
<commit_msg>- Windows compile fix for ha_blackhole.cc - use #include "mysql_priv.h" instead of    #include <mysql_priv.h><commit_after>/* Copyright (C) 2005 MySQL AB

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; either version 2 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA */

#ifdef __GNUC__
#pragma implementation        // gcc: Class implementation
#endif

#include "mysql_priv.h"

#ifdef HAVE_BLACKHOLE_DB
#include "ha_blackhole.h"

const char **ha_blackhole::bas_ext() const
{
  static const char *ext[]= { NullS };
  return ext;
}

int ha_blackhole::open(const char *name, int mode, uint test_if_locked)
{
  DBUG_ENTER("ha_blackhole::open");
  thr_lock_init(&thr_lock);
  thr_lock_data_init(&thr_lock,&lock,NULL);
  DBUG_RETURN(0);
}

int ha_blackhole::close(void)
{
  DBUG_ENTER("ha_blackhole::close");
  thr_lock_delete(&thr_lock);
  DBUG_RETURN(0);
}

int ha_blackhole::create(const char *name, TABLE *table_arg,
                         HA_CREATE_INFO *create_info)
{
  DBUG_ENTER("ha_blackhole::create");
  DBUG_RETURN(0);
}

const char *ha_blackhole::index_type(uint key_number)
{
  DBUG_ENTER("ha_blackhole::index_type");
  DBUG_RETURN((table->key_info[key_number].flags & HA_FULLTEXT) ?
              "FULLTEXT" :
              (table->key_info[key_number].flags & HA_SPATIAL) ?
              "SPATIAL" :
              (table->key_info[key_number].algorithm == HA_KEY_ALG_RTREE) ?
              "RTREE" :
              "BTREE");
}

int ha_blackhole::write_row(byte * buf)
{
  DBUG_ENTER("ha_blackhole::write_row");
  DBUG_RETURN(0);
}

int ha_blackhole::rnd_init(bool scan)
{
  DBUG_ENTER("ha_blackhole::rnd_init");
  DBUG_RETURN(0);
}

int ha_blackhole::rnd_next(byte *buf)
{
  DBUG_ENTER("ha_blackhole::rnd_next");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::rnd_pos(byte * buf, byte *pos)
{
  DBUG_ENTER("ha_blackhole::rnd_pos");
  DBUG_ASSERT(0);
  DBUG_RETURN(0);
}

void ha_blackhole::position(const byte *record)
{
  DBUG_ENTER("ha_blackhole::position");
  DBUG_ASSERT(0);
  DBUG_VOID_RETURN;
}

void ha_blackhole::info(uint flag)
{
  DBUG_ENTER("ha_blackhole::info");

  records= 0;
  deleted= 0;
  errkey= 0;
  mean_rec_length= 0;
  data_file_length= 0;
  index_file_length= 0;
  max_data_file_length= 0;
  delete_length= 0;
  if (flag & HA_STATUS_AUTO)
    auto_increment_value= 1;
  DBUG_VOID_RETURN;
}

int ha_blackhole::external_lock(THD *thd, int lock_type)
{
  DBUG_ENTER("ha_blackhole::external_lock");
  DBUG_RETURN(0);
}

THR_LOCK_DATA **ha_blackhole::store_lock(THD *thd,
                                         THR_LOCK_DATA **to,
                                         enum thr_lock_type lock_type)
{
  *to++= &lock;

  return to;
}

int ha_blackhole::index_read(byte * buf, const byte * key,
                             uint key_len, enum ha_rkey_function find_flag)
{
  DBUG_ENTER("ha_blackhole::index_read");
  DBUG_RETURN(0);
}

int ha_blackhole::index_read_idx(byte * buf, uint idx, const byte * key,
                                 uint key_len, enum ha_rkey_function find_flag)
{
  DBUG_ENTER("ha_blackhole::index_read_idx");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::index_read_last(byte * buf, const byte * key, uint key_len)
{
  DBUG_ENTER("ha_blackhole::index_read_last");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::index_next(byte * buf)
{
  DBUG_ENTER("ha_blackhole::index_next");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::index_prev(byte * buf)
{
  DBUG_ENTER("ha_blackhole::index_prev");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::index_first(byte * buf)
{
  DBUG_ENTER("ha_blackhole::index_first");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

int ha_blackhole::index_last(byte * buf)
{
  DBUG_ENTER("ha_blackhole::index_last");
  DBUG_RETURN(HA_ERR_END_OF_FILE);
}

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


<commit_before>/*
 * copyright: (c) RDO-Team, 2010
 * filename : rdo_rule.cpp
 * author   :  ,
 * date     : 18.08.2010
 * bref     :
 * indent   : 4T
 */

// ====================================================================== INCLUDES
// ====================================================================== SYNOPSIS
#include "rdo_lib/rdo_runtime/pch.h"
#include "rdo_lib/rdo_runtime/rdo_rule.h"
#include "rdo_lib/rdo_runtime/rdo_runtime.h"
// ===============================================================================

OPEN_RDO_RUNTIME_NAMESPACE

// ----------------------------------------------------------------------------
// ---------- RDORule
// ----------------------------------------------------------------------------
RDORule::RDORule( RDORuntime* runtime, RDOPatternRule* pattern, bool trace, const std::string& name )
	: RDOActivityPattern<RDOPatternRule>( runtime, pattern, trace, name )
	, RDOPatternPrior()
	, RDORuntimeContainer  (runtime)
	, m_additionalCondition(NULL   )
{
	init();
}

RDORule::RDORule( RDORuntime* runtime, RDOPatternRule* pattern, bool trace, CREF(LPRDOCalc) pCondition, const std::string& name )
	: RDOActivityPattern<RDOPatternRule>( runtime, pattern, trace, name )
	, RDOPatternPrior()
	, RDORuntimeContainer  (runtime   )
	, m_additionalCondition(pCondition)
{
	init();
}

void RDORule::init()
{
	setTraceID( getRuntime()->getFreeActivityId() );
	m_traceOFF = false;
}

void RDORule::onBeforeChoiceFrom(PTR(rdoRuntime::RDOSimulator) sim)
{
	setPatternParameters(sim);
}

rbool RDORule::choiceFrom(PTR(rdoRuntime::RDORuntime) runtime)
{
	runtime->setCurrentActivity( this );
	if ( m_additionalCondition && !m_additionalCondition->calcValue( runtime ).getAsBool() )
	{
		return false;
	}
	return m_pattern->choiceFrom( runtime );
}

void RDORule::onBeforeRule(PTR(rdoRuntime::RDOSimulator) sim)
{}

void RDORule::convertRule(PTR(rdoRuntime::RDORuntime) runtime)
{
	runtime->setCurrentActivity( this );
	m_pattern->convertRule( runtime );
}

void RDORule::onAfterRule(PTR(rdoRuntime::RDOSimulator) sim, rbool inSearch)
{
	updateConvertStatus( sim, m_pattern->m_convertorStatus );
	if ( !inSearch )
	{
		trace();
	}
	m_pattern->convertErase( static_cast<RDORuntime*>(sim) );
	updateRelRes( sim );
}

void RDORule::trace()
{
	if ( !m_traceOFF )
	{
		getRuntime()->getTracer()->writeRule( this, getRuntime() );
	}
}

bool RDORule::onCheckCondition( RDOSimulator* sim )
{
	onBeforeChoiceFrom( sim );
	sim->inc_cnt_choice_from();
	bool result = choiceFrom( static_cast<RDORuntime*>(sim) );
	if ( result )
	{
		m_traceOFF = true;
		std::auto_ptr<RDOSimulator> clone (sim->clone());
		if (onDoOperation(clone.get()) != IBaseOperation::BOR_done)
		{
			//!    onDoOperation -  -
			return false;
		}
		if ( *clone.get() == *sim )
		{
			result = false;
		}
		m_traceOFF = false;
	}
	return result;
}

IBaseOperation::BOResult RDORule::onDoOperation( RDOSimulator* sim )
{
	onBeforeRule( sim );
	convertRule( static_cast<RDORuntime*>(sim) );
	onAfterRule( sim, false );
	return IBaseOperation::BOR_done;
}

void                     RDORule::onStart     (PTR(rdoRuntime::RDOSimulator) sim)                  {}
void                     RDORule::onStop      (PTR(rdoRuntime::RDOSimulator) sim)                  {}
void                     RDORule::onMakePlaned(PTR(rdoRuntime::RDOSimulator) sim, PTR(void) param) {}
IBaseOperation::BOResult RDORule::onContinue  (PTR(rdoRuntime::RDOSimulator) sim)                  { return IBaseOperation::BOR_cant_run; }

CLOSE_RDO_RUNTIME_NAMESPACE
<commit_msg> - стилистическое форматирование<commit_after>/*
 * copyright: (c) RDO-Team, 2010
 * filename : rdo_rule.cpp
 * author   :  ,
 * date     : 18.08.2010
 * bref     :
 * indent   : 4T
 */

// ====================================================================== INCLUDES
// ====================================================================== SYNOPSIS
#include "rdo_lib/rdo_runtime/pch.h"
#include "rdo_lib/rdo_runtime/rdo_rule.h"
#include "rdo_lib/rdo_runtime/rdo_runtime.h"
// ===============================================================================

OPEN_RDO_RUNTIME_NAMESPACE

// ----------------------------------------------------------------------------
// ---------- RDORule
// ----------------------------------------------------------------------------
RDORule::RDORule( RDORuntime* runtime, RDOPatternRule* pattern, bool trace, const std::string& name )
	: RDOActivityPattern<RDOPatternRule>( runtime, pattern, trace, name )
	, RDOPatternPrior()
	, RDORuntimeContainer  (runtime)
	, m_additionalCondition(NULL   )
{
	init();
}

RDORule::RDORule( RDORuntime* runtime, RDOPatternRule* pattern, bool trace, CREF(LPRDOCalc) pCondition, const std::string& name )
	: RDOActivityPattern<RDOPatternRule>( runtime, pattern, trace, name )
	, RDOPatternPrior()
	, RDORuntimeContainer  (runtime   )
	, m_additionalCondition(pCondition)
{
	init();
}

void RDORule::init()
{
	setTraceID( getRuntime()->getFreeActivityId() );
	m_traceOFF = false;
}

void RDORule::onBeforeChoiceFrom(PTR(rdoRuntime::RDOSimulator) sim)
{
	setPatternParameters(sim);
}

rbool RDORule::choiceFrom(PTR(rdoRuntime::RDORuntime) runtime)
{
	runtime->setCurrentActivity( this );
	if ( m_additionalCondition && !m_additionalCondition->calcValue( runtime ).getAsBool() )
	{
		return false;
	}
	return m_pattern->choiceFrom( runtime );
}

void RDORule::onBeforeRule(PTR(rdoRuntime::RDOSimulator) sim)
{}

void RDORule::convertRule(PTR(rdoRuntime::RDORuntime) runtime)
{
	runtime->setCurrentActivity( this );
	m_pattern->convertRule( runtime );
}

void RDORule::onAfterRule(PTR(rdoRuntime::RDOSimulator) sim, rbool inSearch)
{
	updateConvertStatus( sim, m_pattern->m_convertorStatus );
	if ( !inSearch )
	{
		trace();
	}
	m_pattern->convertErase( static_cast<RDORuntime*>(sim) );
	updateRelRes( sim );
}

void RDORule::trace()
{
	if ( !m_traceOFF )
	{
		getRuntime()->getTracer()->writeRule( this, getRuntime() );
	}
}

bool RDORule::onCheckCondition( RDOSimulator* sim )
{
	onBeforeChoiceFrom( sim );
	sim->inc_cnt_choice_from();
	bool result = choiceFrom( static_cast<RDORuntime*>(sim) );
	if ( result )
	{
		m_traceOFF = true;
		std::auto_ptr<RDOSimulator> clone (sim->clone());
		if (onDoOperation(clone.get()) != IBaseOperation::BOR_done)
		{
			//!    onDoOperation -  -
			return false;
		}
		if ( *clone.get() == *sim )
		{
			result = false;
		}
		m_traceOFF = false;
	}
	return result;
}

IBaseOperation::BOResult RDORule::onDoOperation( RDOSimulator* sim )
{
	onBeforeRule( sim );
	convertRule( static_cast<RDORuntime*>(sim) );
	onAfterRule( sim, false );
	return IBaseOperation::BOR_done;
}

void                     RDORule::onStart     (PTR(rdoRuntime::RDOSimulator) sim)                  {}
void                     RDORule::onStop      (PTR(rdoRuntime::RDOSimulator) sim)                  {}
void                     RDORule::onMakePlaned(PTR(rdoRuntime::RDOSimulator) sim, PTR(void) param) {}
IBaseOperation::BOResult RDORule::onContinue  (PTR(rdoRuntime::RDOSimulator) sim)                  { return IBaseOperation::BOR_cant_run; }

CLOSE_RDO_RUNTIME_NAMESPACE
<|endoftext|>


<commit_before>Copyright 2014 - Transmission Line Software

    This file is part of transmission-line.

    transmission-line is free software: you can redistribute it and/or modify
    it under the terms of the GNU Lesser General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    transmission-line 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 transmission-line.  If not, see <http://www.gnu.org/licenses/>.

#pragma once

#include <list>
#include <vector>
#include <string>

/**
 * @par CABLE COMPONENT OVERVIEW
 *
 * This class models a transmission cable component.
 *
 * @par INPUT VERIFICATION
 *
 * This class contains built-in input verification. To avoid runtime errors when using this class,
 * use the error checking functionality before extracting information.
 */
class CableComponent
{
public:
    /**
     * @brief Default constructor.
     */
    CableComponent();

    /**
     * @brief Destructor.
     */
    ~CableComponent();

    /**
     * @brief Check for errors and warnings in class data.
     * @param includeWarnings An option that includes data warnings in the return list.
     * @return A list of strings containing class data errors/warnings.
     */
    std::list<std::string> CheckData(bool includeWarnings = true) const;

    // member variables
    double					m_ElasticAreaModulus;
    std::vector<double> 	m_LoadStrainCoefficients;
    double					m_ThermalExpansionCoefficient;
};

/**
 * @par CABLE OVERVIEW
 *
 * This class models a transmission cable.
 *
 * @par INPUT VERIFICATION
 *
 * This class contains built-in input verification. To avoid runtime errors when using this class,
 * use the error checking functionality before extracting information.
 */
class Cable
{
public:
    /**
     * @brief Default constructor.
     */
    Cable();

    /**
     * @brief Destructor.
     */
    ~Cable();

    /**
     * @brief Check for errors and warnings in class data.
     * @param includeWarnings An option that includes data warnings in the return list.
     * @return A list of strings containing class data errors/warnings.
     */
    std::list<std::string> CheckData(bool includeWarnings = true) const;

    // member variables
    double          m_Area_CrossSection;
    double			m_Area_Electrical;
    CableComponent	m_Core;
    double			m_Diameter;
    std::string 	m_Name;
    double 			m_RatedBreakingStrength;
    CableComponent	m_Shell;
    double 			m_Temperature_LoadStrainCoefficients;
    std::string		m_Type;
    double			m_UnitWeight;
};
<commit_msg>Remove license - add to public domain.<commit_after>#pragma once

#include <list>
#include <vector>
#include <string>

/**
 * @par CABLE COMPONENT OVERVIEW
 *
 * This class models a transmission cable component.
 *
 * @par INPUT VERIFICATION
 *
 * This class contains built-in input verification. To avoid runtime errors when using this class,
 * use the error checking functionality before extracting information.
 */
class CableComponent
{
public:
    /**
     * @brief Default constructor.
     */
    CableComponent();

    /**
     * @brief Destructor.
     */
    ~CableComponent();

    /**
     * @brief Check for errors and warnings in class data.
     * @param includeWarnings An option that includes data warnings in the return list.
     * @return A list of strings containing class data errors/warnings.
     */
    std::list<std::string> CheckData(bool includeWarnings = true) const;

    // member variables
    double					m_ElasticAreaModulus;
    std::vector<double> 	m_LoadStrainCoefficients;
    double					m_ThermalExpansionCoefficient;
};

/**
 * @par CABLE OVERVIEW
 *
 * This class models a transmission cable.
 *
 * @par INPUT VERIFICATION
 *
 * This class contains built-in input verification. To avoid runtime errors when using this class,
 * use the error checking functionality before extracting information.
 */
class Cable
{
public:
    /**
     * @brief Default constructor.
     */
    Cable();

    /**
     * @brief Destructor.
     */
    ~Cable();

    /**
     * @brief Check for errors and warnings in class data.
     * @param includeWarnings An option that includes data warnings in the return list.
     * @return A list of strings containing class data errors/warnings.
     */
    std::list<std::string> CheckData(bool includeWarnings = true) const;

    // member variables
    double          m_Area_CrossSection;
    double			m_Area_Electrical;
    CableComponent	m_Core;
    double			m_Diameter;
    std::string 	m_Name;
    double 			m_RatedBreakingStrength;
    CableComponent	m_Shell;
    double 			m_Temperature_LoadStrainCoefficients;
    std::string		m_Type;
    double			m_UnitWeight;
};
<|endoftext|>


<commit_before>/*
    kopete.cpp

    Kopete Instant Messenger Main Class

    Copyright (c) 2001-2002  by Duncan Mac-Vicar Prett   <duncan@kde.org>
    Copyright (c) 2002-2003  by Martijn Klingens         <klingens@kde.org>

    Kopete    (c) 2001-2003  by the Kopete developers    <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "kopeteapplication.h"

#include <qtimer.h>
#include <qregexp.h>

#include <kconfig.h>
#include <kdebug.h>
#include <klocale.h>
#include <kcmdlineargs.h>
#include <kmessagebox.h>

#include "addaccountwizard.h"
#include "kabcpersistence.h"
#include "kopeteaccount.h"
#include "kopeteaccountmanager.h"
#include "kopetecommandhandler.h"
#include "kopetecontactlist.h"
#include "kopeteglobal.h"
#include "kopetemimesourcefactory.h"
#include "kopetemimetypehandler.h"
#include "kopetepluginmanager.h"
#include "kopeteprotocol.h"
#include "kopetestdaction.h"
#include "kopeteuiglobal.h"
#include "kopetewindow.h"
#include "kopeteprefs.h"
#include "kopeteviewmanager.h"
#include "videodevice.h"

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

KopeteApplication::KopeteApplication()
: KUniqueApplication( true, true, true )
{
	m_isShuttingDown = false;
	m_mainWindow = new KopeteWindow( 0, "mainWindow" );

	Kopete::PluginManager::self();

	Kopete::UI::Global::setMainWidget( m_mainWindow );

	/*
	 * FIXME: This is a workaround for a quite odd problem:
	 * When starting up kopete and the msn plugin gets loaded it can bring up
	 * a messagebox, in case the msg configuration is missing. This messagebox
	 * will result in a QApplication::enter_loop() call, an event loop is
	 * created. At this point however the loop_level is 0, because this is all
	 * still inside the KopeteApplication constructor, before the exec() call from main.
	 * When the messagebox is finished the loop_level will drop down to zero and
	 * QApplication thinks the application shuts down (this is usually the case
	 * when the loop_level goes down to zero) . So it emits aboutToQuit(), to
	 * which KApplication is connected and re-emits shutdown() , to which again
	 * KMainWindow (a KopeteWindow instance exists already) is connected. KMainWindow's
	 * shuttingDown() slot calls queryExit() which results in KopeteWindow::queryExit()
	 * calling unloadPlugins() . This of course is wrong and just shouldn't happen.
	 * The workaround is to simply delay the initialization of all this to a point
	 * where the loop_level is already > 0 . That is why I moved all the code from
	 * the constructor to the initialize() method and added this single-shot-timer
	 * setup. (Simon)
	 *
	 * Additionally, it makes the GUI appear less 'blocking' during startup, so
	 * there is a secondary benefit as well here. (Martijn)
	 */
	QTimer::singleShot( 0, this, SLOT( slotLoadPlugins() ) );

	m_mimeFactory = new Kopete::MimeSourceFactory;
	QMimeSourceFactory::addFactory( m_mimeFactory );

	//Create the emoticon installer
	m_emoticonHandler = new Kopete::EmoticonMimeTypeHandler;
}

KopeteApplication::~KopeteApplication()
{
	kdDebug( 14000 ) << k_funcinfo << endl;

	delete m_mainWindow;
	delete m_emoticonHandler;
	delete m_mimeFactory;
	//kdDebug( 14000 ) << k_funcinfo << "Done" << endl;
}

void KopeteApplication::slotLoadPlugins()
{
	// we have to load the address book early, because calling this enters the Qt event loop when there are remote resources.
	// The plugin manager is written with the assumption that Kopete will not reenter the event loop during plugin load,
	// otherwise lots of things break as plugins are loaded, then contacts are added to incompletely initialised MCLVIs
	Kopete::KABCPersistence::self()->addressBook();

	//Create the command handler (looks silly)
	Kopete::CommandHandler::commandHandler();

	//Create the view manager
	KopeteViewManager::viewManager();

	Kopete::AccountManager::self()->load();
	Kopete::ContactList::self()->load();

	KConfig *config = KGlobal::config();

	// Parse command-line arguments
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

	bool showConfigDialog = false;

	config->setGroup( "Plugins" );

	/* FIXME: This is crap, if something purged that groups but your accounts
	 * are still working kopete will load the necessary plugins but still show the
	 * stupid accounts dialog (of course empty at that time because account data
	 * gets loaded later on). [mETz - 29.05.2004]
	 */
	if ( !config->hasGroup( "Plugins" ) )
		showConfigDialog = true;

	// Listen to arguments
	/*
	// TODO: conflicts with emoticon installer and the general meaning
	// of %U in kopete.desktop
	if ( args->count() > 0 )
	{
		showConfigDialog = false;
		for ( int i = 0; i < args->count(); i++ )
			Kopete::PluginManager::self()->setPluginEnabled( args->arg( i ), true );
	}
	*/

	// Prevent plugins from loading? (--disable=foo,bar)
	QStringList disableArgs = QStringList::split( ',', args->getOption( "disable" ) );
	for ( QStringList::ConstIterator it = disableArgs.begin(); it != disableArgs.end(); ++it )
	{
		showConfigDialog = false;
		Kopete::PluginManager::self()->setPluginEnabled( *it, false );
	}

	// Load some plugins exclusively? (--load-plugins=foo,bar)
	if ( args->isSet( "load-plugins" ) )
	{
		config->deleteGroup( "Plugins", true );
		showConfigDialog = false;
		QStringList plugins = QStringList::split( ',', args->getOption( "load-plugins" ) );
		for ( QStringList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it )
			Kopete::PluginManager::self()->setPluginEnabled( *it, true );
	}

	config->sync();

	// Disable plugins altogether? (--noplugins)
	if ( !args->isSet( "plugins" ) )
	{
		// If anybody reenables this I'll get a sword and make a nice chop-suy out
		// of your body :P [mETz - 29.05.2004]
		// This screws up kopeterc because there is no way to get the Plugins group back!
		//config->deleteGroup( "Plugins", true );

		showConfigDialog = false;
		// pretend all plugins were loaded :)
		QTimer::singleShot(0, this, SLOT( slotAllPluginsLoaded() ));
	}
	else
	{
		Kopete::PluginManager::self()->loadAllPlugins();
	}

	connect( Kopete::PluginManager::self(), SIGNAL( allPluginsLoaded() ),
		this, SLOT( slotAllPluginsLoaded() ));

	if( showConfigDialog )
	{
		// No plugins specified. Show the config dialog.
		// FIXME: Although it's a bit stupid it is theoretically possible that a user
		//        explicitly configured Kopete to not load plugins on startup. In this
		//        case we don't want this dialog. We need some other config setting
		//        like a bool hasRunKopeteBefore or so to trigger the loading of the
		//        wizard. Maybe using the last run version number is more useful even
		//        as it also allows for other features. - Martijn
		// FIXME: Possibly we need to influence the showConfigDialog bool based on the
		//        command line arguments processed below. But how exactly? - Martijn
		// NB: the command line args are completely broken atm.
		// I don't want to fix them for 3.5 as plugin loading will change for KDE4.	- Will
		AddAccountWizard *m_addwizard = new AddAccountWizard( Kopete::UI::Global::mainWidget(), "addAccountWizard", true, true );
		m_addwizard->exec();
		Kopete::AccountManager::self()->save();
	}
}

void KopeteApplication::slotAllPluginsLoaded()
{
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

	// --noconnect not specified?
	if ( args->isSet( "connect" )  && KopetePrefs::prefs()->autoConnect() )
		Kopete::AccountManager::self()->connectAll();

	QCStringList connectArgs = args->getOptionList( "autoconnect" );
	for ( QCStringList::ConstIterator i = connectArgs.begin(); i != connectArgs.end(); ++i )
	{
		QString id = QString::fromLatin1( *i );

		QRegExp rx( QString::fromLatin1( "([^\\|]*)\\|\\|(.*)" ) );
		rx.search( id );
		QString protocolId = rx.cap( 1 );
		QString accountId = rx.cap( 2 );

		if ( accountId.isEmpty() )
		{
			if ( protocolId.isEmpty() )
				accountId = id;
			else
				continue;
		}

		QPtrListIterator<Kopete::Account> it( Kopete::AccountManager::self()->accounts() );
		Kopete::Account *account;
		while ( ( account = it.current() ) != 0 )
		{
			++it;

			if ( ( account->accountId() == accountId ) )
			{
				if ( protocolId.isEmpty() || account->protocol()->pluginId() == protocolId )
				{
					account->connect();
					break;
				}
			}
		}
	}

	// Parse any passed URLs/files
	handleURLArgs();
}

int KopeteApplication::newInstance()
{
//	kdDebug(14000) << k_funcinfo << endl;
	handleURLArgs();

	/**
	 * The following three lines work around a problem that
	 * Kopete has since it has multiple main windows so
	 * qapp->mainWidget() returns 0, which breaks the normal
	 * KUniqueApplication::newInstance() behavior that raises
	 * the window when we run a new instance.
	 *
	 * 1. Set the main widget to the contact list window
	 * 2. Call KUniqueApplication::newInstance()
	 * 3. Set the main widget back to 0
	 *
	 * This little workaround fixes the problem. -Matt
	 */

	setMainWidget( m_mainWindow );
	int kUniqAppReturnCode = KUniqueApplication::newInstance();
	setMainWidget( 0L );

	return kUniqAppReturnCode;
}

void KopeteApplication::handleURLArgs()
{
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
//	kdDebug(14000) << k_funcinfo << "called with " << args->count() << " arguments to handle." << endl;

	if ( args->count() > 0 )
	{
		for ( int i = 0; i < args->count(); i++ )
		{
			KURL u( args->url( i ) );
			if ( !u.isValid() )
				continue;

			Kopete::MimeTypeHandler::dispatchURL( u );
		} // END for()
	} // END args->count() > 0
}

void KopeteApplication::quitKopete()
{
	kdDebug( 14000 ) << k_funcinfo << endl;

	m_isShuttingDown = true;

	// close all windows
	QPtrListIterator<KMainWindow> it(*KMainWindow::memberList);
	for (it.toFirst(); it.current(); ++it)
	{
		if ( !it.current()->close() )
		{
			m_isShuttingDown = false;
			break;
		}
	}
}

void KopeteApplication::commitData( QSessionManager &sm )
{
	m_isShuttingDown = true;
	KUniqueApplication::commitData( sm );
}

#include "kopeteapplication.moc"
// vim: set noet ts=4 sts=4 sw=4:
<commit_msg>Apply for KDE 3.5 also.<commit_after>/*
    kopete.cpp

    Kopete Instant Messenger Main Class

    Copyright (c) 2001-2002  by Duncan Mac-Vicar Prett   <duncan@kde.org>
    Copyright (c) 2002-2003  by Martijn Klingens         <klingens@kde.org>

    Kopete    (c) 2001-2003  by the Kopete developers    <kopete-devel@kde.org>

    *************************************************************************
    *                                                                       *
    * This program is free software; you can redistribute it and/or modify  *
    * it under the terms of the GNU General Public License as published by  *
    * the Free Software Foundation; either version 2 of the License, or     *
    * (at your option) any later version.                                   *
    *                                                                       *
    *************************************************************************
*/

#include "kopeteapplication.h"

#include <qtimer.h>
#include <qregexp.h>

#include <kconfig.h>
#include <kdebug.h>
#include <klocale.h>
#include <kcmdlineargs.h>
#include <kmessagebox.h>

#include "addaccountwizard.h"
#include "kabcpersistence.h"
#include "kopeteaccount.h"
#include "kopeteaccountmanager.h"
#include "kopetecommandhandler.h"
#include "kopetecontactlist.h"
#include "kopeteglobal.h"
#include "kopetemimesourcefactory.h"
#include "kopetemimetypehandler.h"
#include "kopetepluginmanager.h"
#include "kopeteprotocol.h"
#include "kopetestdaction.h"
#include "kopeteuiglobal.h"
#include "kopetewindow.h"
#include "kopeteprefs.h"
#include "kopeteviewmanager.h"
#include "videodevice.h"

#ifdef HAVE_CONFIG_H
#include <config.h>
#endif

KopeteApplication::KopeteApplication()
: KUniqueApplication( true, true, true )
{
	m_isShuttingDown = false;
	m_mainWindow = new KopeteWindow( 0, "mainWindow" );

	Kopete::PluginManager::self();

	Kopete::UI::Global::setMainWidget( m_mainWindow );

	/*
	 * FIXME: This is a workaround for a quite odd problem:
	 * When starting up kopete and the msn plugin gets loaded it can bring up
	 * a messagebox, in case the msg configuration is missing. This messagebox
	 * will result in a QApplication::enter_loop() call, an event loop is
	 * created. At this point however the loop_level is 0, because this is all
	 * still inside the KopeteApplication constructor, before the exec() call from main.
	 * When the messagebox is finished the loop_level will drop down to zero and
	 * QApplication thinks the application shuts down (this is usually the case
	 * when the loop_level goes down to zero) . So it emits aboutToQuit(), to
	 * which KApplication is connected and re-emits shutdown() , to which again
	 * KMainWindow (a KopeteWindow instance exists already) is connected. KMainWindow's
	 * shuttingDown() slot calls queryExit() which results in KopeteWindow::queryExit()
	 * calling unloadPlugins() . This of course is wrong and just shouldn't happen.
	 * The workaround is to simply delay the initialization of all this to a point
	 * where the loop_level is already > 0 . That is why I moved all the code from
	 * the constructor to the initialize() method and added this single-shot-timer
	 * setup. (Simon)
	 *
	 * Additionally, it makes the GUI appear less 'blocking' during startup, so
	 * there is a secondary benefit as well here. (Martijn)
	 */
	QTimer::singleShot( 0, this, SLOT( slotLoadPlugins() ) );

	m_mimeFactory = new Kopete::MimeSourceFactory;
	QMimeSourceFactory::addFactory( m_mimeFactory );

	//Create the emoticon installer
	m_emoticonHandler = new Kopete::EmoticonMimeTypeHandler;
}

KopeteApplication::~KopeteApplication()
{
	kdDebug( 14000 ) << k_funcinfo << endl;

	delete m_mainWindow;
	delete m_emoticonHandler;
	delete m_mimeFactory;
	//kdDebug( 14000 ) << k_funcinfo << "Done" << endl;
}

void KopeteApplication::slotLoadPlugins()
{
	// we have to load the address book early, because calling this enters the Qt event loop when there are remote resources.
	// The plugin manager is written with the assumption that Kopete will not reenter the event loop during plugin load,
	// otherwise lots of things break as plugins are loaded, then contacts are added to incompletely initialised MCLVIs
	Kopete::KABCPersistence::self()->addressBook();

	//Create the command handler (looks silly)
	Kopete::CommandHandler::commandHandler();

	//Create the view manager
	KopeteViewManager::viewManager();

	Kopete::AccountManager::self()->load();
	Kopete::ContactList::self()->load();

	KConfig *config = KGlobal::config();

	// Parse command-line arguments
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

	bool showConfigDialog = false;

	config->setGroup( "Plugins" );

	/* FIXME: This is crap, if something purged that groups but your accounts
	 * are still working kopete will load the necessary plugins but still show the
	 * stupid accounts dialog (of course empty at that time because account data
	 * gets loaded later on). [mETz - 29.05.2004]
	 */
	if ( !config->hasGroup( "Plugins" ) )
		showConfigDialog = true;

	// Listen to arguments
	/*
	// TODO: conflicts with emoticon installer and the general meaning
	// of %U in kopete.desktop
	if ( args->count() > 0 )
	{
		showConfigDialog = false;
		for ( int i = 0; i < args->count(); i++ )
			Kopete::PluginManager::self()->setPluginEnabled( args->arg( i ), true );
	}
	*/

	// Prevent plugins from loading? (--disable=foo,bar)
	QStringList disableArgs = QStringList::split( ',', args->getOption( "disable" ) );
	for ( QStringList::ConstIterator it = disableArgs.begin(); it != disableArgs.end(); ++it )
	{
		showConfigDialog = false;
		Kopete::PluginManager::self()->setPluginEnabled( *it, false );
	}

	// Load some plugins exclusively? (--load-plugins=foo,bar)
	if ( args->isSet( "load-plugins" ) )
	{
		config->deleteGroup( "Plugins", true );
		showConfigDialog = false;
		QStringList plugins = QStringList::split( ',', args->getOption( "load-plugins" ) );
		for ( QStringList::ConstIterator it = plugins.begin(); it != plugins.end(); ++it )
			Kopete::PluginManager::self()->setPluginEnabled( *it, true );
	}

	config->sync();

	// Disable plugins altogether? (--noplugins)
	if ( !args->isSet( "plugins" ) )
	{
		// If anybody reenables this I'll get a sword and make a nice chop-suy out
		// of your body :P [mETz - 29.05.2004]
		// This screws up kopeterc because there is no way to get the Plugins group back!
		//config->deleteGroup( "Plugins", true );

		showConfigDialog = false;
		// pretend all plugins were loaded :)
		QTimer::singleShot(0, this, SLOT( slotAllPluginsLoaded() ));
	}
	else
	{
		Kopete::PluginManager::self()->loadAllPlugins();
	}

	connect( Kopete::PluginManager::self(), SIGNAL( allPluginsLoaded() ),
		this, SLOT( slotAllPluginsLoaded() ));

	if( showConfigDialog )
	{
		// No plugins specified. Show the config dialog.
		// FIXME: Although it's a bit stupid it is theoretically possible that a user
		//        explicitly configured Kopete to not load plugins on startup. In this
		//        case we don't want this dialog. We need some other config setting
		//        like a bool hasRunKopeteBefore or so to trigger the loading of the
		//        wizard. Maybe using the last run version number is more useful even
		//        as it also allows for other features. - Martijn
		// FIXME: Possibly we need to influence the showConfigDialog bool based on the
		//        command line arguments processed below. But how exactly? - Martijn
		// NB: the command line args are completely broken atm.
		// I don't want to fix them for 3.5 as plugin loading will change for KDE4.	- Will
		AddAccountWizard *m_addwizard = new AddAccountWizard( Kopete::UI::Global::mainWidget(), "addAccountWizard", true, true );
		m_addwizard->exec();
		Kopete::AccountManager::self()->save();
	}
}

void KopeteApplication::slotAllPluginsLoaded()
{
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();

	// --noconnect not specified?
	if ( args->isSet( "connect" )  && KopetePrefs::prefs()->autoConnect() )
		Kopete::AccountManager::self()->connectAll();

	// Handle things like '--autoconnect foo,bar --autoconnect foobar'
	QCStringList connectArgsC = args->getOptionList( "autoconnect" );
	QStringList connectArgs;

	for ( QCStringList::ConstIterator it = connectArgsC.begin(); it != connectArgsC.end(); ++it )
	{
		QStringList split = QStringList::split( ',', QString::fromLatin1( *it ) );

		for ( QStringList::ConstIterator it2 = split.begin(); it2 != split.end(); ++it2 )
		{
			connectArgs.append( *it2 );
		}
	}

	for ( QStringList::ConstIterator i = connectArgs.begin(); i != connectArgs.end(); ++i )
	{
		QRegExp rx( QString::fromLatin1( "([^\\|]*)\\|\\|(.*)" ) );
		rx.search( *i );
		QString protocolId = rx.cap( 1 );
		QString accountId = rx.cap( 2 );

		if ( accountId.isEmpty() )
		{
			if ( protocolId.isEmpty() )
				accountId = *i;
			else
				continue;
		}

		QPtrListIterator<Kopete::Account> it( Kopete::AccountManager::self()->accounts() );
		Kopete::Account *account;
		while ( ( account = it.current() ) != 0 )
		{
			++it;

			if ( ( account->accountId() == accountId ) )
			{
				if ( protocolId.isEmpty() || account->protocol()->pluginId() == protocolId )
				{
					account->connect();
					break;
				}
			}
		}
	}

	// Parse any passed URLs/files
	handleURLArgs();
}

int KopeteApplication::newInstance()
{
//	kdDebug(14000) << k_funcinfo << endl;
	handleURLArgs();

	/**
	 * The following three lines work around a problem that
	 * Kopete has since it has multiple main windows so
	 * qapp->mainWidget() returns 0, which breaks the normal
	 * KUniqueApplication::newInstance() behavior that raises
	 * the window when we run a new instance.
	 *
	 * 1. Set the main widget to the contact list window
	 * 2. Call KUniqueApplication::newInstance()
	 * 3. Set the main widget back to 0
	 *
	 * This little workaround fixes the problem. -Matt
	 */

	setMainWidget( m_mainWindow );
	int kUniqAppReturnCode = KUniqueApplication::newInstance();
	setMainWidget( 0L );

	return kUniqAppReturnCode;
}

void KopeteApplication::handleURLArgs()
{
	KCmdLineArgs *args = KCmdLineArgs::parsedArgs();
//	kdDebug(14000) << k_funcinfo << "called with " << args->count() << " arguments to handle." << endl;

	if ( args->count() > 0 )
	{
		for ( int i = 0; i < args->count(); i++ )
		{
			KURL u( args->url( i ) );
			if ( !u.isValid() )
				continue;

			Kopete::MimeTypeHandler::dispatchURL( u );
		} // END for()
	} // END args->count() > 0
}

void KopeteApplication::quitKopete()
{
	kdDebug( 14000 ) << k_funcinfo << endl;

	m_isShuttingDown = true;

	// close all windows
	QPtrListIterator<KMainWindow> it(*KMainWindow::memberList);
	for (it.toFirst(); it.current(); ++it)
	{
		if ( !it.current()->close() )
		{
			m_isShuttingDown = false;
			break;
		}
	}
}

void KopeteApplication::commitData( QSessionManager &sm )
{
	m_isShuttingDown = true;
	KUniqueApplication::commitData( sm );
}

#include "kopeteapplication.moc"
// vim: set noet ts=4 sts=4 sw=4:
<|endoftext|>


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

#include "bucketmovejobv2.h"
#include "imaintenancejobrunner.h"
#include "ibucketstatechangednotifier.h"
#include "iclusterstatechangednotifier.h"
#include "maintenancedocumentsubdb.h"
#include "i_disk_mem_usage_notifier.h"
#include "ibucketmodifiedhandler.h"
#include "move_operation_limiter.h"
#include "document_db_maintenance_config.h"
#include <vespa/searchcore/proton/bucketdb/i_bucket_create_notifier.h>
#include <vespa/searchcore/proton/feedoperation/moveoperation.h>
#include <vespa/searchcore/proton/documentmetastore/i_document_meta_store.h>
#include <vespa/searchcorespi/index/i_thread_service.h>
#include <vespa/persistence/spi/bucket_tasks.h>
#include <vespa/vespalib/util/destructor_callbacks.h>
#include <vespa/vespalib/util/lambdatask.h>

#include <vespa/log/log.h>
LOG_SETUP(".proton.server.bucketmovejob");

using document::BucketId;
using storage::spi::BucketInfo;
using storage::spi::Bucket;
using storage::spi::makeBucketTask;
using proton::bucketdb::BucketMover;
using vespalib::makeLambdaTask;

namespace proton {

namespace {

const char * bool2str(bool v) { return (v ? "T" : "F"); }

bool
blockedDueToClusterState(const IBucketStateCalculator::SP &calc)
{
    bool clusterUp = calc && calc->clusterUp();
    bool nodeUp = calc && calc->nodeUp();
    bool nodeInitializing = calc && calc->nodeInitializing();
    return !(clusterUp && nodeUp && !nodeInitializing);
}

}

BucketMoveJobV2::BucketMoveJobV2(const IBucketStateCalculator::SP &calc,
                                 IDocumentMoveHandler &moveHandler,
                                 IBucketModifiedHandler &modifiedHandler,
                                 IThreadService & master,
                                 BucketExecutor & bucketExecutor,
                                 const MaintenanceDocumentSubDB &ready,
                                 const MaintenanceDocumentSubDB &notReady,
                                 bucketdb::IBucketCreateNotifier &bucketCreateNotifier,
                                 IClusterStateChangedNotifier &clusterStateChangedNotifier,
                                 IBucketStateChangedNotifier &bucketStateChangedNotifier,
                                 IDiskMemUsageNotifier &diskMemUsageNotifier,
                                 const BlockableMaintenanceJobConfig &blockableConfig,
                                 const vespalib::string &docTypeName,
                                 document::BucketSpace bucketSpace)
    : BlockableMaintenanceJob("move_buckets." + docTypeName, vespalib::duration::zero(), vespalib::duration::zero(), blockableConfig),
      IClusterStateChangedHandler(),
      bucketdb::IBucketCreateListener(),
      IBucketStateChangedHandler(),
      IDiskMemUsageListener(),
      _calc(calc),
      _moveHandler(moveHandler),
      _modifiedHandler(modifiedHandler),
      _master(master),
      _bucketExecutor(bucketExecutor),
      _ready(ready),
      _notReady(notReady),
      _bucketSpace(bucketSpace),
      _iterateCount(0),
      _movers(),
      _buckets2Move(),
      _stopped(false),
      _startedCount(0),
      _executedCount(0),
      _bucketCreateNotifier(bucketCreateNotifier),
      _clusterStateChangedNotifier(clusterStateChangedNotifier),
      _bucketStateChangedNotifier(bucketStateChangedNotifier),
      _diskMemUsageNotifier(diskMemUsageNotifier)
{
    _movers.reserve(std::min(100u, blockableConfig.getMaxOutstandingMoveOps()));
    if (blockedDueToClusterState(_calc)) {
        setBlocked(BlockedReason::CLUSTER_STATE);
    }

    _bucketCreateNotifier.addListener(this);
    _clusterStateChangedNotifier.addClusterStateChangedHandler(this);
    _bucketStateChangedNotifier.addBucketStateChangedHandler(this);
    _diskMemUsageNotifier.addDiskMemUsageListener(this);
    recompute();
}

BucketMoveJobV2::~BucketMoveJobV2()
{
    _bucketCreateNotifier.removeListener(this);
    _clusterStateChangedNotifier.removeClusterStateChangedHandler(this);
    _bucketStateChangedNotifier.removeBucketStateChangedHandler(this);
    _diskMemUsageNotifier.removeDiskMemUsageListener(this);
}

BucketMoveJobV2::NeedResult
BucketMoveJobV2::needMove(const ScanIterator &itr) const {
    NeedResult noMove(false, false);
    const bool hasReadyDocs = itr.hasReadyBucketDocs();
    const bool hasNotReadyDocs = itr.hasNotReadyBucketDocs();
    if (!hasReadyDocs && !hasNotReadyDocs) {
        return noMove; // No documents for bucket in ready or notready subdbs
    }
    const bool isActive = itr.isActive();
    // No point in moving buckets when node is retired and everything will be deleted soon.
    // However, allow moving of explicitly activated buckets, as this implies a lack of other good replicas.
    if (!_calc || (_calc->nodeRetired() && !isActive)) {
        return noMove;
    }
    const bool shouldBeReady = _calc->shouldBeReady(document::Bucket(_bucketSpace, itr.getBucket()));
    const bool wantReady = shouldBeReady || isActive;
    LOG(spam, "checkBucket(): bucket(%s), shouldBeReady(%s), active(%s)",
        itr.getBucket().toString().c_str(), bool2str(shouldBeReady), bool2str(isActive));
    if (wantReady) {
        if (!hasNotReadyDocs)
            return noMove; // No notready bucket to make ready
    } else {
        if (isActive)
            return noMove; // Do not move rom ready to not ready when active
        if (!hasReadyDocs)
            return noMove; // No ready bucket to make notready
    }
    return {true, wantReady};
}

void
BucketMoveJobV2::startMove(BucketMoverSP mover, size_t maxDocsToMove) {
    auto [keys, done] = mover->getKeysToMove(maxDocsToMove);
    if (done) {
        mover->setBucketDone();
    }
    if (keys.empty()) return;
    if (_stopped.load(std::memory_order_relaxed)) return;
    mover->updateLastValidGid(keys.back()._gid);
    auto context = getLimiter().beginOperation();
    Bucket spiBucket(document::Bucket(_bucketSpace, mover->getBucket()));
    auto bucketTask = makeBucketTask(
            [this, mover=std::move(mover), keys=std::move(keys),opsTracker=getLimiter().beginOperation()]
            (const Bucket & bucket, std::shared_ptr<IDestructorCallback> onDone) mutable
    {
        assert(mover->getBucket() == bucket.getBucketId());
        using DoneContext = vespalib::KeepAlive<std::pair<IDestructorCallbackSP, IDestructorCallbackSP>>;
        prepareMove(std::move(mover), std::move(keys),
                    std::make_shared<DoneContext>(std::make_pair(std::move(opsTracker), std::move(onDone))));
    });
    auto failed = _bucketExecutor.execute(spiBucket, std::move(bucketTask));
    if (!failed) {
        _startedCount.fetch_add(1, std::memory_order_relaxed);
    }
}

namespace {

class IncOnDestruct {
public:
    IncOnDestruct(std::atomic<size_t> & count) : _count(count) {}
    ~IncOnDestruct() {
        _count.fetch_add(1, std::memory_order_relaxed);
    }
private:
    std::atomic<size_t> & _count;
};

}

void
BucketMoveJobV2::prepareMove(BucketMoverSP mover, std::vector<MoveKey> keys, IDestructorCallbackSP onDone)
{
    IncOnDestruct countGuard(_executedCount);
    if (_stopped.load(std::memory_order_relaxed)) return;
    auto moveOps = mover->createMoveOperations(keys);
    _master.execute(makeLambdaTask([this, mover=std::move(mover), moveOps=std::move(moveOps), onDone=std::move(onDone)]() mutable {
        completeMove(std::move(mover), std::move(moveOps), std::move(onDone));
    }));
}

void
BucketMoveJobV2::completeMove(BucketMoverSP mover, std::vector<GuardedMoveOp> ops, IDestructorCallbackSP onDone) {
    mover->moveDocuments(std::move(ops), std::move(onDone));
    if (mover->bucketDone() && mover->inSync()) {
        _modifiedHandler.notifyBucketModified(mover->getBucket());
    }
}

void
BucketMoveJobV2::cancelMovesForBucket(BucketId bucket) {
    for (auto itr = _movers.begin(); itr != _movers.end(); itr++) {
        if (bucket == (*itr)->getBucket()) {
            _movers.erase(itr);
            backFillMovers();
            return;
        }
    }
}

void
BucketMoveJobV2::considerBucket(const bucketdb::Guard & guard, BucketId bucket)
{
    ScanIterator itr(guard, bucket);
    auto [mustMove, wantReady] = needMove(itr);
    if (mustMove) {
        _buckets2Move[bucket] = wantReady;
    } else {
        _buckets2Move.erase(bucket);
        cancelMovesForBucket(bucket);
    }
    backFillMovers();
    considerRun();
}

void
BucketMoveJobV2::notifyCreateBucket(const bucketdb::Guard & guard, const BucketId &bucket)
{
    considerBucket(guard, bucket);
}

BucketMoveJobV2::BucketSet
BucketMoveJobV2::computeBuckets2Move()
{
    BucketMoveJobV2::BucketSet toMove;
    for (ScanIterator itr(_ready.meta_store()->getBucketDB().takeGuard(), BucketId()); itr.valid(); ++itr) {
        auto [mustMove, wantReady] = needMove(itr);
        if (mustMove) {
            toMove[itr.getBucket()] = wantReady;
        }
    }
    return toMove;
}

std::shared_ptr<BucketMover>
BucketMoveJobV2::createMover(BucketId bucket, bool wantReady) {
    const MaintenanceDocumentSubDB &source(wantReady ? _notReady : _ready);
    const MaintenanceDocumentSubDB &target(wantReady ? _ready : _notReady);
    LOG(debug, "checkBucket(): mover.setupForBucket(%s, source:%u, target:%u)",
        bucket.toString().c_str(), source.sub_db_id(), target.sub_db_id());
    return std::make_shared<BucketMover>(bucket, &source, target.sub_db_id(), _moveHandler);
}

std::shared_ptr<BucketMover>
BucketMoveJobV2::greedyCreateMover() {
    if ( ! _buckets2Move.empty()) {
        auto next = _buckets2Move.begin();
        auto mover = createMover(next->first, next->second);
        _buckets2Move.erase(next->first);
        return mover;
    }
    return {};
}

bool
BucketMoveJobV2::moveDocs(size_t maxDocsToMove) {
    if (done()) return true;

    // Select mover
    size_t index = _iterateCount++ % _movers.size();
    const auto & mover = _movers[index];

    //Move, or reduce movers as we are tailing off
    if (!mover->bucketDone()) {
        startMove(mover, maxDocsToMove);
        if (mover->bucketDone()) {
            auto next = greedyCreateMover();
            if (next) {
                _movers[index] = next;
            } else {
                _movers.erase(_movers.begin() + index);
            }
        }
    }
    return done();
}

bool
BucketMoveJobV2::scanAndMove(size_t maxBuckets2Move, size_t maxDocsToMovePerBucket) {
    for (size_t i(0); i < maxBuckets2Move; i++) {
        moveDocs(maxDocsToMovePerBucket);
    }
    return isBlocked() || done();
}

bool
BucketMoveJobV2::done() const {
    return _buckets2Move.empty() && _movers.empty() && !isBlocked();
}

bool
BucketMoveJobV2::run()
{
    if (isBlocked()) {
        return true; // indicate work is done, since node state is bad
    }
    /// Returning false here will immediately post the job back on the executor. This will give a busy loop,
    /// but this is considered fine as it is very rare and it will be intermingled with multiple feed operations.
    if ( ! scanAndMove(1, 1) ) {
        return false;
    }

    if (isBlocked(BlockedReason::OUTSTANDING_OPS)) {
        return true;
    }
    return done();
}

void
BucketMoveJobV2::recompute() {
    _movers.clear();
    _buckets2Move = computeBuckets2Move();
    backFillMovers();
}

void
BucketMoveJobV2::backFillMovers() {
    // Ensure we have enough movers.
    while ( ! _buckets2Move.empty() && (_movers.size() < _movers.capacity())) {
        _movers.push_back(greedyCreateMover());
    }
}
void
BucketMoveJobV2::notifyClusterStateChanged(const IBucketStateCalculator::SP &newCalc)
{
    // Called by master write thread
    _calc = newCalc;
    recompute();
    if (blockedDueToClusterState(_calc)) {
        setBlocked(BlockedReason::CLUSTER_STATE);
    } else {
        unBlock(BlockedReason::CLUSTER_STATE);
    }
}

void
BucketMoveJobV2::notifyBucketStateChanged(const BucketId &bucketId, BucketInfo::ActiveState)
{
    // Called by master write thread
    considerBucket(_ready.meta_store()->getBucketDB().takeGuard(), bucketId);
}

void
BucketMoveJobV2::notifyDiskMemUsage(DiskMemUsageState state)
{
    // Called by master write thread
    internalNotifyDiskMemUsage(state);
}

bool
BucketMoveJobV2::inSync() const {
    return _executedCount == _startedCount;
}

void
BucketMoveJobV2::onStop() {
    // Called by master write thread
    _stopped = true;
    while ( ! inSync() ) {
        std::this_thread::sleep_for(1ms);
    }
}

} // namespace proton
<commit_msg>Use braces and erase with iterator.<commit_after>// Copyright 2017 Yahoo Holdings. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.

#include "bucketmovejobv2.h"
#include "imaintenancejobrunner.h"
#include "ibucketstatechangednotifier.h"
#include "iclusterstatechangednotifier.h"
#include "maintenancedocumentsubdb.h"
#include "i_disk_mem_usage_notifier.h"
#include "ibucketmodifiedhandler.h"
#include "move_operation_limiter.h"
#include "document_db_maintenance_config.h"
#include <vespa/searchcore/proton/bucketdb/i_bucket_create_notifier.h>
#include <vespa/searchcore/proton/feedoperation/moveoperation.h>
#include <vespa/searchcore/proton/documentmetastore/i_document_meta_store.h>
#include <vespa/searchcorespi/index/i_thread_service.h>
#include <vespa/persistence/spi/bucket_tasks.h>
#include <vespa/vespalib/util/destructor_callbacks.h>
#include <vespa/vespalib/util/lambdatask.h>

#include <vespa/log/log.h>
LOG_SETUP(".proton.server.bucketmovejob");

using document::BucketId;
using storage::spi::BucketInfo;
using storage::spi::Bucket;
using storage::spi::makeBucketTask;
using proton::bucketdb::BucketMover;
using vespalib::makeLambdaTask;

namespace proton {

namespace {

const char * bool2str(bool v) { return (v ? "T" : "F"); }

bool
blockedDueToClusterState(const IBucketStateCalculator::SP &calc)
{
    bool clusterUp = calc && calc->clusterUp();
    bool nodeUp = calc && calc->nodeUp();
    bool nodeInitializing = calc && calc->nodeInitializing();
    return !(clusterUp && nodeUp && !nodeInitializing);
}

}

BucketMoveJobV2::BucketMoveJobV2(const IBucketStateCalculator::SP &calc,
                                 IDocumentMoveHandler &moveHandler,
                                 IBucketModifiedHandler &modifiedHandler,
                                 IThreadService & master,
                                 BucketExecutor & bucketExecutor,
                                 const MaintenanceDocumentSubDB &ready,
                                 const MaintenanceDocumentSubDB &notReady,
                                 bucketdb::IBucketCreateNotifier &bucketCreateNotifier,
                                 IClusterStateChangedNotifier &clusterStateChangedNotifier,
                                 IBucketStateChangedNotifier &bucketStateChangedNotifier,
                                 IDiskMemUsageNotifier &diskMemUsageNotifier,
                                 const BlockableMaintenanceJobConfig &blockableConfig,
                                 const vespalib::string &docTypeName,
                                 document::BucketSpace bucketSpace)
    : BlockableMaintenanceJob("move_buckets." + docTypeName, vespalib::duration::zero(), vespalib::duration::zero(), blockableConfig),
      IClusterStateChangedHandler(),
      bucketdb::IBucketCreateListener(),
      IBucketStateChangedHandler(),
      IDiskMemUsageListener(),
      _calc(calc),
      _moveHandler(moveHandler),
      _modifiedHandler(modifiedHandler),
      _master(master),
      _bucketExecutor(bucketExecutor),
      _ready(ready),
      _notReady(notReady),
      _bucketSpace(bucketSpace),
      _iterateCount(0),
      _movers(),
      _buckets2Move(),
      _stopped(false),
      _startedCount(0),
      _executedCount(0),
      _bucketCreateNotifier(bucketCreateNotifier),
      _clusterStateChangedNotifier(clusterStateChangedNotifier),
      _bucketStateChangedNotifier(bucketStateChangedNotifier),
      _diskMemUsageNotifier(diskMemUsageNotifier)
{
    _movers.reserve(std::min(100u, blockableConfig.getMaxOutstandingMoveOps()));
    if (blockedDueToClusterState(_calc)) {
        setBlocked(BlockedReason::CLUSTER_STATE);
    }

    _bucketCreateNotifier.addListener(this);
    _clusterStateChangedNotifier.addClusterStateChangedHandler(this);
    _bucketStateChangedNotifier.addBucketStateChangedHandler(this);
    _diskMemUsageNotifier.addDiskMemUsageListener(this);
    recompute();
}

BucketMoveJobV2::~BucketMoveJobV2()
{
    _bucketCreateNotifier.removeListener(this);
    _clusterStateChangedNotifier.removeClusterStateChangedHandler(this);
    _bucketStateChangedNotifier.removeBucketStateChangedHandler(this);
    _diskMemUsageNotifier.removeDiskMemUsageListener(this);
}

BucketMoveJobV2::NeedResult
BucketMoveJobV2::needMove(const ScanIterator &itr) const {
    NeedResult noMove(false, false);
    const bool hasReadyDocs = itr.hasReadyBucketDocs();
    const bool hasNotReadyDocs = itr.hasNotReadyBucketDocs();
    if (!hasReadyDocs && !hasNotReadyDocs) {
        return noMove; // No documents for bucket in ready or notready subdbs
    }
    const bool isActive = itr.isActive();
    // No point in moving buckets when node is retired and everything will be deleted soon.
    // However, allow moving of explicitly activated buckets, as this implies a lack of other good replicas.
    if (!_calc || (_calc->nodeRetired() && !isActive)) {
        return noMove;
    }
    const bool shouldBeReady = _calc->shouldBeReady(document::Bucket(_bucketSpace, itr.getBucket()));
    const bool wantReady = shouldBeReady || isActive;
    LOG(spam, "checkBucket(): bucket(%s), shouldBeReady(%s), active(%s)",
        itr.getBucket().toString().c_str(), bool2str(shouldBeReady), bool2str(isActive));
    if (wantReady) {
        if (!hasNotReadyDocs) {
            return noMove; // No notready bucket to make ready
        }
    } else {
        if (isActive) {
            return noMove; // Do not move rom ready to not ready when active
        }
        if (!hasReadyDocs) {
            return noMove; // No ready bucket to make notready
        }
    }
    return {true, wantReady};
}

void
BucketMoveJobV2::startMove(BucketMoverSP mover, size_t maxDocsToMove) {
    auto [keys, done] = mover->getKeysToMove(maxDocsToMove);
    if (done) {
        mover->setBucketDone();
    }
    if (keys.empty()) return;
    if (_stopped.load(std::memory_order_relaxed)) return;
    mover->updateLastValidGid(keys.back()._gid);
    auto context = getLimiter().beginOperation();
    Bucket spiBucket(document::Bucket(_bucketSpace, mover->getBucket()));
    auto bucketTask = makeBucketTask(
            [this, mover=std::move(mover), keys=std::move(keys),opsTracker=getLimiter().beginOperation()]
            (const Bucket & bucket, std::shared_ptr<IDestructorCallback> onDone) mutable
    {
        assert(mover->getBucket() == bucket.getBucketId());
        using DoneContext = vespalib::KeepAlive<std::pair<IDestructorCallbackSP, IDestructorCallbackSP>>;
        prepareMove(std::move(mover), std::move(keys),
                    std::make_shared<DoneContext>(std::make_pair(std::move(opsTracker), std::move(onDone))));
    });
    auto failed = _bucketExecutor.execute(spiBucket, std::move(bucketTask));
    if (!failed) {
        _startedCount.fetch_add(1, std::memory_order_relaxed);
    }
}

namespace {

class IncOnDestruct {
public:
    IncOnDestruct(std::atomic<size_t> & count) : _count(count) {}
    ~IncOnDestruct() {
        _count.fetch_add(1, std::memory_order_relaxed);
    }
private:
    std::atomic<size_t> & _count;
};

}

void
BucketMoveJobV2::prepareMove(BucketMoverSP mover, std::vector<MoveKey> keys, IDestructorCallbackSP onDone)
{
    IncOnDestruct countGuard(_executedCount);
    if (_stopped.load(std::memory_order_relaxed)) return;
    auto moveOps = mover->createMoveOperations(keys);
    _master.execute(makeLambdaTask([this, mover=std::move(mover), moveOps=std::move(moveOps), onDone=std::move(onDone)]() mutable {
        completeMove(std::move(mover), std::move(moveOps), std::move(onDone));
    }));
}

void
BucketMoveJobV2::completeMove(BucketMoverSP mover, std::vector<GuardedMoveOp> ops, IDestructorCallbackSP onDone) {
    mover->moveDocuments(std::move(ops), std::move(onDone));
    if (mover->bucketDone() && mover->inSync()) {
        _modifiedHandler.notifyBucketModified(mover->getBucket());
    }
}

void
BucketMoveJobV2::cancelMovesForBucket(BucketId bucket) {
    for (auto itr = _movers.begin(); itr != _movers.end(); itr++) {
        if (bucket == (*itr)->getBucket()) {
            _movers.erase(itr);
            backFillMovers();
            return;
        }
    }
}

void
BucketMoveJobV2::considerBucket(const bucketdb::Guard & guard, BucketId bucket)
{
    ScanIterator itr(guard, bucket);
    auto [mustMove, wantReady] = needMove(itr);
    if (mustMove) {
        _buckets2Move[bucket] = wantReady;
    } else {
        _buckets2Move.erase(bucket);
        cancelMovesForBucket(bucket);
    }
    backFillMovers();
    considerRun();
}

void
BucketMoveJobV2::notifyCreateBucket(const bucketdb::Guard & guard, const BucketId &bucket)
{
    considerBucket(guard, bucket);
}

BucketMoveJobV2::BucketSet
BucketMoveJobV2::computeBuckets2Move()
{
    BucketMoveJobV2::BucketSet toMove;
    for (ScanIterator itr(_ready.meta_store()->getBucketDB().takeGuard(), BucketId()); itr.valid(); ++itr) {
        auto [mustMove, wantReady] = needMove(itr);
        if (mustMove) {
            toMove[itr.getBucket()] = wantReady;
        }
    }
    return toMove;
}

std::shared_ptr<BucketMover>
BucketMoveJobV2::createMover(BucketId bucket, bool wantReady) {
    const MaintenanceDocumentSubDB &source(wantReady ? _notReady : _ready);
    const MaintenanceDocumentSubDB &target(wantReady ? _ready : _notReady);
    LOG(debug, "checkBucket(): mover.setupForBucket(%s, source:%u, target:%u)",
        bucket.toString().c_str(), source.sub_db_id(), target.sub_db_id());
    return std::make_shared<BucketMover>(bucket, &source, target.sub_db_id(), _moveHandler);
}

std::shared_ptr<BucketMover>
BucketMoveJobV2::greedyCreateMover() {
    if ( ! _buckets2Move.empty()) {
        auto next = _buckets2Move.begin();
        auto mover = createMover(next->first, next->second);
        _buckets2Move.erase(next);
        return mover;
    }
    return {};
}

bool
BucketMoveJobV2::moveDocs(size_t maxDocsToMove) {
    if (done()) return true;

    // Select mover
    size_t index = _iterateCount++ % _movers.size();
    const auto & mover = _movers[index];

    //Move, or reduce movers as we are tailing off
    if (!mover->bucketDone()) {
        startMove(mover, maxDocsToMove);
        if (mover->bucketDone()) {
            auto next = greedyCreateMover();
            if (next) {
                _movers[index] = next;
            } else {
                _movers.erase(_movers.begin() + index);
            }
        }
    }
    return done();
}

bool
BucketMoveJobV2::scanAndMove(size_t maxBuckets2Move, size_t maxDocsToMovePerBucket) {
    for (size_t i(0); i < maxBuckets2Move; i++) {
        moveDocs(maxDocsToMovePerBucket);
    }
    return isBlocked() || done();
}

bool
BucketMoveJobV2::done() const {
    return _buckets2Move.empty() && _movers.empty() && !isBlocked();
}

bool
BucketMoveJobV2::run()
{
    if (isBlocked()) {
        return true; // indicate work is done, since node state is bad
    }
    /// Returning false here will immediately post the job back on the executor. This will give a busy loop,
    /// but this is considered fine as it is very rare and it will be intermingled with multiple feed operations.
    if ( ! scanAndMove(1, 1) ) {
        return false;
    }

    if (isBlocked(BlockedReason::OUTSTANDING_OPS)) {
        return true;
    }
    return done();
}

void
BucketMoveJobV2::recompute() {
    _movers.clear();
    _buckets2Move = computeBuckets2Move();
    backFillMovers();
}

void
BucketMoveJobV2::backFillMovers() {
    // Ensure we have enough movers.
    while ( ! _buckets2Move.empty() && (_movers.size() < _movers.capacity())) {
        _movers.push_back(greedyCreateMover());
    }
}
void
BucketMoveJobV2::notifyClusterStateChanged(const IBucketStateCalculator::SP &newCalc)
{
    // Called by master write thread
    _calc = newCalc;
    recompute();
    if (blockedDueToClusterState(_calc)) {
        setBlocked(BlockedReason::CLUSTER_STATE);
    } else {
        unBlock(BlockedReason::CLUSTER_STATE);
    }
}

void
BucketMoveJobV2::notifyBucketStateChanged(const BucketId &bucketId, BucketInfo::ActiveState)
{
    // Called by master write thread
    considerBucket(_ready.meta_store()->getBucketDB().takeGuard(), bucketId);
}

void
BucketMoveJobV2::notifyDiskMemUsage(DiskMemUsageState state)
{
    // Called by master write thread
    internalNotifyDiskMemUsage(state);
}

bool
BucketMoveJobV2::inSync() const {
    return _executedCount == _startedCount;
}

void
BucketMoveJobV2::onStop() {
    // Called by master write thread
    _stopped = true;
    while ( ! inSync() ) {
        std::this_thread::sleep_for(1ms);
    }
}

} // namespace proton
<|endoftext|>


<commit_before>/**
 * \file
 * \brief MutexPriorityProtocolTestCase class header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-04
 */

#ifndef TEST_MUTEX_MUTEXPRIORITYPROTOCOLTESTCASE_HPP_
#define TEST_MUTEX_MUTEXPRIORITYPROTOCOLTESTCASE_HPP_

#include "TestCase.hpp"

namespace distortos
{

namespace test
{

/**
 * \brief Executes typical "priority inversion" scenario using mutexes with PriorityProtect protocol.
 *
 * 5 threads are executed and they are expected to execute and preempt each other in exact sequence.
 */

class MutexPriorityProtocolTestCase : public TestCase
{
private:

	/**
	 * \brief Runs the test case.
	 *
	 * \return true if the test case succeeded, false otherwise
	 */

	virtual bool run_() const override;
};

}	// namespace test

}	// namespace distortos

#endif	// TEST_MUTEX_MUTEXPRIORITYPROTOCOLTESTCASE_HPP_
<commit_msg>test: add doxygen description of MutexPriorityProtocolTestCase (with images)<commit_after>/**
 * \file
 * \brief MutexPriorityProtocolTestCase class header
 *
 * \author Copyright (C) 2014 Kamil Szczygiel http://www.distortec.com http://www.freddiechopin.info
 *
 * \par License
 * This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not
 * distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * \date 2014-11-05
 */

#ifndef TEST_MUTEX_MUTEXPRIORITYPROTOCOLTESTCASE_HPP_
#define TEST_MUTEX_MUTEXPRIORITYPROTOCOLTESTCASE_HPP_

#include "TestCase.hpp"

namespace distortos
{

namespace test
{

/**
 * \brief Executes typical "priority inversion" scenario using mutexes with PriorityProtect protocol.
 *
 * 5 threads are executed and they are expected to execute and preempt each other in exact sequence.
 *
 * Legend for timing diagrams:
 * - Lxx - lock of mutex xx
 * - Uxx - unlock of mutex xx
 * - x12 - operation on mutex shared between T1 and T2
 * - x13 - operation on mutex shared between T1 and T3
 * - x23 - operation on mutex shared between T2 and T3
 * - x35 - operation on mutex shared between T3 and T5
 * - solid outline with background - thread is running
 * - dashed outline without background - thread is preempted
 * - gray background - thread doesn't hold any mutexes
 * - orange background - thread holds one mutex
 * - red background - thread holds two mutexes
 * - pink background - thread holds three mutexes
 * - arrows - priority changes due to operation of PriorityProtect protocol
 *
 * Vertical scale - priority, T1 - lowest, T5 - highest
 * Horizontal scale - time
 *
 * \image html without-priority-protect-scenario.png "Without \"PriorityProtect\" protocol enabled"
 *
 * This scenario demonstrates typical priority inversion problem - highest priority thread T5 is delayed because lower
 * priority thread T4 executes and doesn't allow other lower priority threads (which hold mutex required by thread T5)
 * to continue. This is what happens in each marked time point:
 * - at t0 thread T1 starts executing
 * - at t1 thread T1 successfully locks mutex "13"
 * - at t2 thread T1 successfully locks mutex "12"
 * - at t3 thread T2 starts executing and preempts thread T1
 * - at t4 thread T2 successfully locks mutex "23"
 * - at t5 thread T2 tries to lock mutex "12" which is currently held by thread T1, thread T1 is allowed to continue,
 * - at t6 thread T3 starts executing and preempts thread T1
 * - at t7 thread T3 successfully locks mutex "35"
 * - at t8 thread T2 tries to lock mutex "23" which is currently held by thread T2, thread T1 is allowed to continue (as
 * thread T2 is blocked on mutex "12")
 * - at t9 thread T4 starts executing and preempts thread T1
 * - at t10 thread T5 starts executing and preempts thread T4
 * - at t11 thread T5 tries to lock mutex "35" which is currently held by thread T3, thread T4 is allowed to continue as
 * a thread with highest priority that is "runnable"
 * - at t12 thread T4 terminates and allows thread T1 to continue (as thread T5 is blocked on mutex "35", thread T3 - on
 * mutex "23" and thread T2 - on mutex "12")
 * - at t13 thread T1 unlocks mutex "13"
 * - at t14 thread T1 unlocks mutex "12", ownership of the mutex is passed to thread T2, which is allowed to continue
 * - at t15 thread T2 unlocks mutex "23", ownership of the mutex is passed to thread T3, which is allowed to continue
 * - at t16 thread T3 successfully locks mutex "13"
 * - at t17 thread T3 unlocks mutex "35", ownership of the mutex is passed to thread T5, which is allowed to continue
 * - at t18 thread T5 unlocks mutex "35"
 * - at t19 thread T5 terminates and allows thread T3 to continue
 * - at t20 thread T3 unlocks mutex "23"
 * - at t21 thread T3 unlocks mutex "13"
 * - at t22 thread T3 terminates and allows thread T2 to continue
 * - at t23 thread T2 unlocks mutex "12"
 * - at t24 thread T2 terminates and allows thread T1 to continue
 * - at t25 thread T1 terminates
 *
 * \image html with-priority-protect-scenario.png "With \"PriorityProtect\" protocol enabled"
 *
 * This is the same situation as in previous scenario, but now all mutexes have PriorityProtect protocol enabled.
 * Changes of priority due to this protocol allow highest priority thread T5 to acquire ownership of the mutex much
 * sooner than previously. Additionally the most important critical sections (where mutex with high priority ceiling is
 * used) are as short as possible. This scenario has 9 context switches, which is much less than 16 in scenario without
 * PriorityProtect protocol. This is what happens in each marked time point:
 * - at t0 thread T1 starts executing
 * - at t1 thread T1 successfully locks mutex "13" and it's priority is boosted to the priority ceiling of this mutex,
 * which is equal to priority of thread T3
 * - at t2 thread T1 successfully locks mutex "12", there is no priority boost as priority ceiling of mutex "12" is
 * lower than priority ceiling of mutex "13"
 * - at t3 thread T2 becomes "runnable", but is not allowed to run because effective priority of thread T1 is higher
 * - at t4 thread T3 becomes "runnable", but is not allowed to run because effective priority of thread T1 is equal and
 * thread T1 was first
 * - at t5 thread T1 unlocks mutex "13" and it's priority is lowered to the priority ceiling of another mutex it holds
 * ("12"), which is equal to priority of thread T2, thread T1 is preempted and thread T3 is allowed to continue
 * - at t6 thread T3 successfully locks mutex "35" and it's priority is boosted to the priority ceiling of this mutex,
 * which is equal to priority of thread T5
 * - at t7 thread T3 successfully locks mutex "23", there is no priority boost as priority ceiling of mutex "23" is
 * lower than priority ceiling of mutex "35"
 * - at t8 thread T3 successfully locks mutex "13", there is no priority boost as priority ceiling of mutex "13" is
 * lower than priority ceiling of mutex "35", thread T4 becomes "runnable", but is not allowed to run because effective
 * priority of thread T3 is higher
 * - at t9 thread T5 becomes "runnable", but is not allowed to run because effective priority of thread T3 is equal and
 * thread T3 was first
 * - at t10 thread T3 unlocks mutex "35" and it's priority is lowered to its original value (other mutexes it currently
 * holds - "23" and "13" - have priority ceiling equal to priority of thread T3), thread T3 is preempted and thread T5
 * is allowed to continue
 * - at t11 thread T5 successfully locks mutex "35", there is no priority boost as priority ceiling of mutex "35" is
 * equal to original priority of thread T5
 * - at t12 thread T5 unlocks mutex "35"
 * - at t13 thread T5 terminates and allows thread T4 to continue
 * - at t14 thread T4 terminates and allows thread T3 to continue
 * - at t15 thread T3 unlocks mutex "23"
 * - at t16 thread T3 unlocks mutex "13"
 * - at t17 thread T3 terminates and allows thread T1 (its effective priority is equal to priority of thread T2, but
 * thread T1 was first) to continue
 * - at t18 thread T1 unlocks mutex "12" and it's priority is lowered to its original value, thread T1 is preempted and
 * thread T2 is allowed to continue
 * - at t19 thread T2 successfully locks mutex "23" and it's priority is boosted to the priority ceiling of this mutex,
 * which is equal to priority of thread T3
 * - at t20 thread T2 successfully locks mutex "12", there is no priority boost as priority ceiling of mutex "12" is
 * lower than priority ceiling of mutex "23"
 * - at t21 thread T2 unlocks mutex "23" and it's priority is lowered to its original value
 * - at t22 thread T2 unlocks mutex "12"
 * - at t23 thread T2 terminates and allows thread T1 to continue
 * - at t24 thread T1 terminates
 */

class MutexPriorityProtocolTestCase : public TestCase
{
private:

	/**
	 * \brief Runs the test case.
	 *
	 * \return true if the test case succeeded, false otherwise
	 */

	virtual bool run_() const override;
};

}	// namespace test

}	// namespace distortos

#endif	// TEST_MUTEX_MUTEXPRIORITYPROTOCOLTESTCASE_HPP_
<|endoftext|>


<commit_before><commit_msg>update usage instructions of pocheck tool<commit_after><|endoftext|>


<commit_before>
#pragma once

#include <functional>
#include <limits>
#include <vector>

#include "base/array.hpp"
#include "quantities/named_quantities.hpp"

namespace principia {
namespace numerics {
namespace internal_root_finders {

using base::BoundedArray;
using quantities::Derivative;

// Approximates a root of |f| between |lower_bound| and |upper_bound| by
// bisection.  The result is less than one ULP from a root of any continuous
// function agreeing with |f| on the values of |Argument|.
// If |f(lower_bound)| and |f(upper_bound)| are both nonzero, they must be of
// opposite signs.
template<typename Argument, typename Function>
Argument Bisect(Function f,
                Argument const& lower_bound,
                Argument const& upper_bound);

// Performs Brent’s procedure |zero| from [Bre73], chapter 4, with an absolute
// tolerance t=0.
template<typename Argument, typename Function>
Argument Brent(Function f,
               Argument const& lower_bound,
               Argument const& upper_bound);

// Performs a golden-section search to find a local extremum of |f| between
// |lower_bound| and |upper_bound|.
// The function searches for a minimum if compare is <, and a maximum if compare
// is >.  Arbitrary order relations are allowed; in general, this function
// searches for a value x such that compare(y, f(x)) is false for all y in some
// neighbourhood of x.
template<typename Argument, typename Function, typename Compare>
Argument GoldenSectionSearch(Function f,
                             Argument const& lower_bound,
                             Argument const& upper_bound,
                             Compare compare);

// Performs Brent’s procedure |localmin| from [Bre73], chapter 5, with an
// absolute tolerance t set to the (subnormal) smallest strictly positive value
// of |Difference<Argument>|.
// The function searches for a minimum if compare is <, and a maximum if compare
// is >.  No values of Compare other than std::less<> and std::greater<> are
// allowed.
// The default value of |eps| is √ϵ, for ϵ as defined in [Bre73], chapter 4,
// (2.9).
template<typename Argument, typename Function, typename Compare>
Argument Brent(
    Function f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    Compare compare,
    double eps = Sqrt(ScaleB(0.5, 1 - std::numeric_limits<double>::digits)));

// Returns the solutions of the quadratic equation:
//   a2 * (x - origin)^2 + a1 * (x - origin) + a0 == 0
// The result may have 0, 1 or 2 values and is sorted.
template<typename Argument, typename Value>
BoundedArray<Argument, 2> SolveQuadraticEquation(
    Argument const& origin,
    Value const& a0,
    Derivative<Value, Argument> const& a1,
    Derivative<Derivative<Value, Argument>, Argument> const& a2);

}  // namespace internal_root_finders

using internal_root_finders::Bisect;
using internal_root_finders::Brent;
using internal_root_finders::GoldenSectionSearch;
using internal_root_finders::SolveQuadraticEquation;

}  // namespace numerics
}  // namespace principia

#include "numerics/root_finders_body.hpp"
<commit_msg>Errors found by Clang.<commit_after>
#pragma once

#include <functional>
#include <limits>
#include <vector>

#include "base/array.hpp"
#include "numerics/scale_b.h"
#include "quantities/elementary_functions.hpp"
#include "quantities/named_quantities.hpp"

namespace principia {
namespace numerics {
namespace internal_root_finders {

using base::BoundedArray;
using quantities::Derivative;
using quantities::Sqrt;

// Approximates a root of |f| between |lower_bound| and |upper_bound| by
// bisection.  The result is less than one ULP from a root of any continuous
// function agreeing with |f| on the values of |Argument|.
// If |f(lower_bound)| and |f(upper_bound)| are both nonzero, they must be of
// opposite signs.
template<typename Argument, typename Function>
Argument Bisect(Function f,
                Argument const& lower_bound,
                Argument const& upper_bound);

// Performs Brent’s procedure |zero| from [Bre73], chapter 4, with an absolute
// tolerance t=0.
template<typename Argument, typename Function>
Argument Brent(Function f,
               Argument const& lower_bound,
               Argument const& upper_bound);

// Performs a golden-section search to find a local extremum of |f| between
// |lower_bound| and |upper_bound|.
// The function searches for a minimum if compare is <, and a maximum if compare
// is >.  Arbitrary order relations are allowed; in general, this function
// searches for a value x such that compare(y, f(x)) is false for all y in some
// neighbourhood of x.
template<typename Argument, typename Function, typename Compare>
Argument GoldenSectionSearch(Function f,
                             Argument const& lower_bound,
                             Argument const& upper_bound,
                             Compare compare);

// Performs Brent’s procedure |localmin| from [Bre73], chapter 5, with an
// absolute tolerance t set to the (subnormal) smallest strictly positive value
// of |Difference<Argument>|.
// The function searches for a minimum if compare is <, and a maximum if compare
// is >.  No values of Compare other than std::less<> and std::greater<> are
// allowed.
// The default value of |eps| is √ϵ, for ϵ as defined in [Bre73], chapter 4,
// (2.9).
template<typename Argument, typename Function, typename Compare>
Argument Brent(
    Function f,
    Argument const& lower_bound,
    Argument const& upper_bound,
    Compare compare,
    double eps = Sqrt(ScaleB(0.5, 1 - std::numeric_limits<double>::digits)));

// Returns the solutions of the quadratic equation:
//   a2 * (x - origin)^2 + a1 * (x - origin) + a0 == 0
// The result may have 0, 1 or 2 values and is sorted.
template<typename Argument, typename Value>
BoundedArray<Argument, 2> SolveQuadraticEquation(
    Argument const& origin,
    Value const& a0,
    Derivative<Value, Argument> const& a1,
    Derivative<Derivative<Value, Argument>, Argument> const& a2);

}  // namespace internal_root_finders

using internal_root_finders::Bisect;
using internal_root_finders::Brent;
using internal_root_finders::GoldenSectionSearch;
using internal_root_finders::SolveQuadraticEquation;

}  // namespace numerics
}  // namespace principia

#include "numerics/root_finders_body.hpp"
<|endoftext|>