// SPDX-FileCopyrightText: 2020-2026 Sven Breuner and elbencho contributors
// SPDX-License-Identifier: GPL-3.0-only

#ifndef COMMON_H_
#define COMMON_H_

#include <boost/config.hpp> // for BOOST_LIKELY
#include <cstdint>
#include <list>
#include <set>
#include <string>
#include <unistd.h>
#include <vector>

// macro to easily switch between AWS Common Runtime (CRT) includes and external libs runtime

#ifdef S3_AWSCRT
    #define INCLUDE_AWS_S3(FILEPATH) <aws/s3-crt/FILEPATH>
#else
    #define INCLUDE_AWS_S3(FILEPATH) <aws/s3/FILEPATH>
#endif

// common types

typedef std::list<std::string> StringList;
typedef std::set<std::string> StringSet;
typedef std::vector<std::string> StringVec;
typedef std::vector<int> IntVec;
typedef std::vector<char*> BufferVec;
typedef std::vector<size_t> SizeTVec;
typedef std::vector<uint64_t> UInt64Vec;


#define STRINGIZE(value)		_STRINGIZE(value) // 2 levels necessary for macro expansion
#define _STRINGIZE(value)		#value


/**
 * Human-readable benchmark phase names for enum BenchPhase.
 * TranslatorTk::benchPhaseToPhaseName() does the conversion.
 */
#define PHASENAME_IDLE          "IDLE"
#define PHASENAME_TERMINATE     "QUIT"
#define PHASENAME_CREATEDIRS    "MKDIRS"
#define PHASENAME_CREATEBUCKETS "MKBUCKETS"
#define PHASENAME_CREATEFILES   "WRITE"
#define PHASENAME_READFILES     "READ"
#define PHASENAME_DELETEFILES   "RMFILES"
#define PHASENAME_DELETEOBJECTS "RMOBJECTS"
#define PHASENAME_DELETEDIRS    "RMDIRS"
#define PHASENAME_DELETEBUCKETS "RMBUCKETS"
#define PHASENAME_SYNC          "SYNC"
#define PHASENAME_DROPCACHES    "DROPCACHE"
#define PHASENAME_STATFILES     "STAT"
#define PHASENAME_STATOBJECTS   "HEADOBJ"
#define PHASENAME_STATDIRS      "STATDIRS"
#define PHASENAME_LISTOBJECTS   "LISTOBJ"
#define PHASENAME_LISTOBJPAR    "LISTOBJ_P"
#define PHASENAME_MULTIDELOBJ   "MULTIDEL"
#define PHASENAME_PUTOBJACL     "PUTOBJACL"
#define PHASENAME_GETOBJACL     "GETOBJACL"
#define PHASENAME_PUTBUCKETACL  "PUTBACL"
#define PHASENAME_GETBUCKETACL  "GETBACL"
#define PHASENAME_S3MPUCOMPLETE "MPUCOMPL"

// special S3 metadata phases for multiple metadata operation types
#define PHASENAME_GETOBJECTMETADATA     "GETOBJMD"
#define PHASENAME_PUTOBJECTMETADATA     "PUTOBJMD"
#define PHASENAME_DELOBJECTMETADATA     "DELOBJMD"
#define PHASENAME_GETBUCKETMETADATA     "GETBUCKETMD"
#define PHASENAME_PUTBUCKETMETADATA     "PUTBUCKETMD"
#define PHASENAME_DELBUCKETMETADATA     "DELBUCKETMD"


/**
 * Human-readable entry type in current benchmark phase.
 *
 * TranslatorTk::benchPhaseToPhaseEntryType() returns these based on enum BenchPhase.
 */

#define PHASEENTRYTYPE_DIRS     "dirs"
#define PHASEENTRYTYPE_FILES    "files"
#define PHASEENTRYTYPE_BUCKETS  "buckets"
#define PHASEENTRYTYPE_OBJECTS  "objects"

/*
 * Messaging protocol version. Exchanged between master and services to check compatibility.
 * (Only exact matches are assumed to be compatible, that's why this can differ from the program
 * version.)
 */
#define HTTP_PROTOCOLVERSION	"3.1.2"

/**
 * Default access mode bits for new files.
 */
#define MKFILE_MODE				(S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH)

/**
 * Call delete() on an object pointer if it's not NULL and afterwards set it to NULL.
 */
#define SAFE_DELETE(objectPointer) \
	do \
	{ \
		if(objectPointer) \
		{ \
			delete(objectPointer); \
			objectPointer = NULL; \
		}  \
	} while(0)

/**
 * Call free on a pointer if it's not NULL and afterwards set it to NULL.
 */
#define SAFE_FREE(pointer) \
	do \
	{ \
		if(pointer) \
		{ \
			free(pointer); \
			pointer = NULL; \
		}  \
	} while(0)


// tell the compiler that a code path is likely/unlikely to optimize performance of "good" paths
#ifdef BOOST_UNLIKELY
	#define IF_UNLIKELY(condition)	if(BOOST_UNLIKELY(condition) )
	#define IF_LIKELY(condition)	if(BOOST_LIKELY(!!(condition) ) )
#else // fallback for older boost versions
	#define IF_UNLIKELY(condition)	if(__builtin_expect(condition, 0) )
	#define IF_LIKELY(condition)	if(__builtin_expect(!!(condition), 1) )
#endif

/**
 * std::string() macro to change "/var/tmp" to %TEMP% env var on windows.
 * (no trailing slash included.)
 */
#ifdef CYGWIN_SUPPORT
    #define ELBENCHO_VAR_TMP        std::string(getenv("TEMP") ? \
                                        getenv("TEMP") : "C:/Windows/Temp")
#else
    #define ELBENCHO_VAR_TMP        std::string("/var/tmp")
#endif // CYGWIN_SUPPORT


/**
 * Current benchmark mode.
 */
 enum BenchMode
 {
    BenchMode_UNDEFINED = 0,
    BenchMode_POSIX,
    BenchMode_S3,
    BenchMode_HDFS,
    BenchMode_NETBENCH,
 };

/**
 * Current benchmark phase.
 *
 * Each phase needs to:
 * - be in Coordinator::runBenchmarks() for phase execution ordering
 * - have a PHASENAME_xx definition for the human-readable name
 *   - (incl conversion via TranslatorTk::benchPhaseToPhaseName() )
 * - be in TranslatorTk::benchPhaseToPhaseEntryType() for conversion to entry type
 * - be in WorkerManager::getPhaseNumEntriesAndBytes for progress reporting
 * - be in RemoteWorker::run to be sent to service instances
 * - be in LocalWorker::run to call the appropriate action method
 */
enum BenchPhase
{
	BenchPhase_IDLE = 0,
	BenchPhase_TERMINATE, // tells workers to self-terminate when all is done
	BenchPhase_CREATEDIRS,
	BenchPhase_DELETEDIRS,
	BenchPhase_CREATEFILES,
	BenchPhase_DELETEFILES,
	BenchPhase_READFILES,
	BenchPhase_SYNC,
	BenchPhase_DROPCACHES,
	BenchPhase_STATFILES,
    BenchPhase_STATDIRS,
	BenchPhase_LISTOBJECTS,
	BenchPhase_LISTOBJPARALLEL,
	BenchPhase_MULTIDELOBJ,
	BenchPhase_PUTOBJACL,
	BenchPhase_GETOBJACL,
	BenchPhase_PUTBUCKETACL,
	BenchPhase_GETBUCKETACL,
    BenchPhase_GET_S3_OBJECT_MD,
    BenchPhase_PUT_S3_OBJECT_MD,
    BenchPhase_DEL_S3_OBJECT_MD,
    BenchPhase_GET_S3_BUCKET_MD,
    BenchPhase_PUT_S3_BUCKET_MD,
    BenchPhase_DEL_S3_BUCKET_MD,
	BenchPhase_S3MPUCOMPLETE,
};


/**
 * Type of user-given benchmark paths.
 */
enum BenchPathType
{
	BenchPathType_DIR=0, // also used for s3
	BenchPathType_FILE=1,
	BenchPathType_BLOCKDEV=2,
};


/**
 * Retrieved by master from services as part of preparation phase.
 */
struct BenchPathInfo
{
	std::string benchPathStr;
	BenchPathType benchPathType;
	size_t numBenchPaths;
	uint64_t fileSize;
	uint64_t blockSize;
	uint64_t randomAmount;
};

typedef std::vector<BenchPathInfo> BenchPathInfoVec;


// http service paths

#define HTTPCLIENTPATH_INFO                     "/info"
#define HTTPCLIENTPATH_PROTOCOLVERSION          "/protocolversion"
#define HTTPCLIENTPATH_STATUS                   "/status"
#define HTTPCLIENTPATH_BENCHRESULT              "/benchresult"
#define HTTPCLIENTPATH_PREPAREFILE              "/preparefile"
#define HTTPCLIENTPATH_PREPAREPHASE             "/preparephase"
#define HTTPCLIENTPATH_STARTPHASE               "/startphase"
#define HTTPCLIENTPATH_INTERRUPTPHASE           "/interruptphase"

#define MAKE_SERVER_PATH(path)                  "^" path "$"
#define HTTPSERVERPATH_INFO                     MAKE_SERVER_PATH(HTTPCLIENTPATH_INFO)
#define HTTPSERVERPATH_PROTOCOLVERSION          MAKE_SERVER_PATH(HTTPCLIENTPATH_PROTOCOLVERSION)
#define HTTPSERVERPATH_STATUS                   MAKE_SERVER_PATH(HTTPCLIENTPATH_STATUS)
#define HTTPSERVERPATH_BENCHRESULT              MAKE_SERVER_PATH(HTTPCLIENTPATH_BENCHRESULT)
#define HTTPSERVERPATH_PREPAREFILE              MAKE_SERVER_PATH(HTTPCLIENTPATH_PREPAREFILE)
#define HTTPSERVERPATH_PREPAREPHASE             MAKE_SERVER_PATH(HTTPCLIENTPATH_PREPAREPHASE)
#define HTTPSERVERPATH_STARTPHASE               MAKE_SERVER_PATH(HTTPCLIENTPATH_STARTPHASE)
#define HTTPSERVERPATH_INTERRUPTPHASE           MAKE_SERVER_PATH(HTTPCLIENTPATH_INTERRUPTPHASE)


// http service transferred parameters (used as http GET parameters or in json document)

#define XFER_PREP_PROTCOLVERSION				"ProtocolVersion"
#define XFER_PREP_BENCHPATHTYPE					"BenchPathType"
#define XFER_PREP_ERRORHISTORY					"ErrorHistory"
#define XFER_PREP_NUMBENCHPATHS					"NumBenchPaths"
#define XFER_PREP_FILENAME						"FileName"
#define XFER_PREP_AUTHORIZATION                 "PwHash"

#define XFER_STATS_BENCHID 						"BenchID"
#define XFER_STATS_BENCHPHASENAME 				"PhaseName"
#define XFER_STATS_BENCHPHASECODE				"PhaseCode"
#define XFER_STATS_NUMWORKERSDONE				"NumWorkersDone"
#define XFER_STATS_NUMWORKERSDONEWITHERR		"NumWorkersDoneWithError"
#define XFER_STATS_TRIGGERSTONEWALL				"TriggerStoneWall"
#define XFER_STATS_NUMENTRIESDONE 				"NumEntriesDone"
#define XFER_STATS_NUMBYTESDONE 				"NumBytesDone"
#define XFER_STATS_NUMIOPSDONE 					"NumIOPSDone"
#define XFER_STATS_NUMENTRIESDONE_RWMIXREAD		"NumEntriesDoneRWMixRead"
#define XFER_STATS_NUMBYTESDONE_RWMIXREAD		"NumBytesDoneRWMixRead"
#define XFER_STATS_NUMIOPSDONE_RWMIXREAD		"NumIOPSDoneRWMixRead"
#define XFER_STATS_ELAPSEDUSECLIST				"ElapsedUSecList"
#define XFER_STATS_ELAPSEDUSECLIST_ITEM			"ElapsedUSecList.item"
#define XFER_STATS_ELAPSEDSECS 					"ElapsedSecs"
#define XFER_STATS_ERRORHISTORY					XFER_PREP_ERRORHISTORY
#define XFER_STATS_LAT_NUM_IOPS					"NumIOLatUSec"
#define XFER_STATS_LAT_SUM_IOPS					"SumIOLatUSec"
#define XFER_STATS_LAT_NUM_IOPS_RWMIXREAD		"NumIOLatUSecRWMixRead"
#define XFER_STATS_LAT_SUM_IOPS_RWMIXREAD		"SumIOLatUSecRWMixRead"
#define XFER_STATS_LAT_NUM_ENTRIES				"NumEntLatUSec"
#define XFER_STATS_LAT_SUM_ENTRIES				"SumEntLatUSec"
#define XFER_STATS_LAT_NUM_ENTRIES_RWMIXREAD	"NumEntLatUSecRWMixRead"
#define XFER_STATS_LAT_SUM_ENTRIES_RWMIXREAD	"SumEntLatUSecRWMixRead"
#define XFER_STATS_LAT_PREFIX_IOPS				"IOPS_"
#define XFER_STATS_LAT_PREFIX_ENTRIES			"Entries_"
#define XFER_STATS_LAT_PREFIX_IOPS_RWMIXREAD	"IOPSRWMixRead_"
#define XFER_STATS_LAT_PREFIX_ENTRIES_RWMIXREAD	"EntriesRWMixRead_"
#define XFER_STATS_LATMICROSECTOTAL				"LatMicroSecTotal"
#define XFER_STATS_LATNUMVALUES					"LatNumValues"
#define XFER_STATS_LATMINMICROSEC				"LatMinMicroSec"
#define XFER_STATS_LATMAXMICROSEC				"LatMaxMicroSec"
#define XFER_STATS_LATHISTOLIST					"LatHistoList"
#define XFER_STATS_LATHISTOLIST_ITEM			"LatHistoList.item"
#define XFER_STATS_CPUUTIL_STONEWALL			"CPUUtilStoneWall"
#define XFER_STATS_CPUUTIL						"CPUUtil"

#define XFER_START_BENCHID						XFER_STATS_BENCHID
#define XFER_START_BENCHPHASECODE				XFER_STATS_BENCHPHASECODE

#define XFER_INTERRUPT_QUIT						"quit"

#endif /* COMMON_H_ */
