diff --git a/Build/gcc/Makefile b/Build/gcc/Makefile index 622ad45d..ea77ab10 100644 --- a/Build/gcc/Makefile +++ b/Build/gcc/Makefile @@ -77,6 +77,7 @@ INCLUDE_FLAGS = -I$(GENERICS_DIR) \ -I$(SOURCE_DIR)/Parser \ -I$(SOURCE_DIR)/Root \ -I$(SOURCE_DIR)/NameServer \ + -I$(SOURCE_DIR)/NameServer/AddressBook \ -I$(SOURCE_DIR)/Softswitch/inc \ -I$(MPICH_INC_DIR) \ -I$(QT_INC_DIR) \ diff --git a/Build/gcc/Makefile.executable_prerequisites b/Build/gcc/Makefile.executable_prerequisites index 8fa80e05..3d2e2264 100644 --- a/Build/gcc/Makefile.executable_prerequisites +++ b/Build/gcc/Makefile.executable_prerequisites @@ -79,6 +79,13 @@ HARDWARE_FILE_READER_SOURCES = $(SOURCE_DIR)/OrchBase/HardwareFileReader/Hardwar $(GENERICS_DIR)/uif.cpp \ $(HARDWARE_DEPLOYER_SOURCES) +# Sources used by the Address Book object. +ADDRESS_BOOK_SOURCES = $(SOURCE_DIR)/NameServer/AddressBook/AddressBook_Defs.cpp \ + $(SOURCE_DIR)/NameServer/AddressBook/AddressBook_Record.cpp \ + $(SOURCE_DIR)/NameServer/AddressBook/AddressBook_Task.cpp \ + $(SOURCE_DIR)/NameServer/AddressBook/AddressBook.cpp + + # The orchestrate execution script uses a template. ORCHESTRATE_TEMPLATE = ./Resources/orchestrate_template.sh diff --git a/Build/gcc/Makefile.test_prerequisites b/Build/gcc/Makefile.test_prerequisites index 3552996d..0848c54e 100644 --- a/Build/gcc/Makefile.test_prerequisites +++ b/Build/gcc/Makefile.test_prerequisites @@ -29,6 +29,7 @@ TestHardwareIterator_SOURCES = $(HARDWARE_MODEL_SOURCES) TestHardwareModel_SOURCES = $(HARDWARE_MODEL_SOURCES) TestSimpleDeployment_SOURCES = $(HARDWARE_DEPLOYER_SOURCES) TestSoftwareAddress_SOURCES = $(SOFTWARE_ADDRESS_SOURCES) +TestAddressBook_SOURCES = $(ADDRESS_BOOK_SOURCES) # Define test rules. TEST_RULE_TEMPLATE defines the substitutions made in the # foreach loop below. diff --git a/Source/NameServer/AddressBook/AddressBook.cpp b/Source/NameServer/AddressBook/AddressBook.cpp new file mode 100644 index 00000000..4b02c245 --- /dev/null +++ b/Source/NameServer/AddressBook/AddressBook.cpp @@ -0,0 +1,1365 @@ +//============================================================================== +#include "AddressBook.hpp" +//#include "Debug.h" + +#include + +//============================================================================== +namespace AddressBook +{ +//Constructors +AddressBook::AddressBook(std::string d) +{ + AddressBookDerived = d; +} + +AddressBook::~AddressBook() +{ + // Teardown the TaskMap. Everything else should be handled properly. + for(TaskMap_t::iterator T=TaskMap.begin();T!=TaskMap.end();T++) + { + TaskRecord_t* TRec = &(*(T->second)); + delete TRec; + + } +} + + +/*============================================================================== + * GetTaskCount: Get the number of currently loaded tasks + *============================================================================*/ +unsigned AddressBook::GetTaskCount(void) +{ + return TaskMap.size(); +} + +//============================================================================== +//Task Manipulation +unsigned AddressBook::AddTask(const std::string &TaskName, TaskData_t &Data) +{ + // Check that the task does not already exist. + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec != PNULL) + { + //throw("Task Name Already Used"); + return ERR_TASKNAME_USED; + } + + // validate here and exit if the device type data is invalid. These will + // actually be checked again when device types are added below; a duplication, + // but the number of device types and number of message types is going to + // be relatively small, so this isn't going to be too costly + unsigned Ret = ValidateTask(Data); + if(Ret) return Ret; + + // Build a TaskRecord + TaskRecord_t * Task = new TaskRecord_t; + + Task->Name = TaskName; + Task->Path = Data.Path; + Task->XML = Data.XML; + Task->ExecPath = Data.ExecutablePath; + + Task->DevCntMax = Data.DeviceCount; + Task->ExtCntMax = Data.ExternalCount; + + // Pre-reserve the Vectors of Records for consistent pointers. + Task->Devices.reserve(Data.DeviceCount + 1); + Task->Externals.reserve(Data.ExternalCount + 1); + Task->Supervisors.reserve(MAXSUPERVISORS + 1); + + // String Data - copy it over, initialise vectors and create index maps. + // MessageType strings. + Task->MsgTypes.resize(Data.MessageTypes.size()); //pre-alloc vector + std::vector *MTypes = &(Data.MessageTypes); + for(std::vector::const_iterator M=MTypes->begin(); + M!=MTypes->end(); M++) + { + Task->MsgTypes[static_cast(M - MTypes->begin())].Name = *M; + Task->MsgTypeMap.insert(IdxMap_t::value_type(*M, (M-MTypes->begin()))); + } + + // AttributeType strings. + Task->AttrTypes.resize(Data.AttributeTypes.size()); + std::vector *ATypes = &(Data.AttributeTypes); + for(std::vector::const_iterator A=ATypes->begin(); + A!=ATypes->end(); A++) + { + AttrTypePair APair(*A,RecordVect_t()); + Task->AttrTypes[static_cast(A - ATypes->begin())] = APair; + Task->AttrTypeMap.insert(IdxMap_t::value_type(*A, (A-ATypes->begin()))); + } + + // Add to the Task Map. + TaskMap.insert(TaskMap_t::value_type(Task->Name, Task)); + + /* Insert DeviceTypes. Changed order and call subfunction 5 July 2019 ADR + Original had pre-allocation below, but it's hard to see how this + really gains anything because a DevTypeRecord_t contains 2 internal + vectors (which would be zero-initialised) and a resize is thus inevitable + anyway when actual device types are inserted. + + GMB: The pre-allocation here saves potentially disastrous re-allocation + later - the outer vector will not be re-sized when the inner ones are as + the inner vectors are not stored in the continuous memory space of the + outer vector, so inserting the inner vectors will not cause the outer to + reallocate. Added a reserve (rather than resize) back in for expediency. + */ + Task->DevTypes.reserve(Data.DeviceTypes.size()); //pre-alloc vector + std::vector *DTypes = &(Data.DeviceTypes); + for(std::vector::iterator D=DTypes->begin(); + D!=DTypes->end(); D++) + AddDeviceType(Task->Name, *D); // add is bound to succeed because we have + // pre-validated. + return SUCCESS; +} + +/*============================================================================== + * AddDeviceType: Append another device type to the task. + *============================================================================*/ +unsigned AddressBook::AddDeviceType(const std::string &TaskName, const DevTypeRecord_t &DeviceType) +{ + // Check that the task exists. + TaskRecord_t *Task = FindTask(TaskName); + if(Task == PNULL) + { + return ERR_TASK_NOT_FOUND; + } + // and that the new device type has valid message indices + if (unsigned retVal = ValidateDeviceType(DeviceType, Task->MsgTypes.size())) + return retVal; + DevTypePair DPair(DeviceType,RecordVect_t()); + Task->DevTypes.push_back(DPair); + unsigned devTypIdx = Task->DevTypes.size() - 1; + Task->DevTypeMap.insert(IdxMap_t::value_type(DeviceType.Name, devTypIdx)); + + // Cross-ref to Message Types. + for(std::vector::const_iterator I=DeviceType.InMsgs.begin(); + I!=DeviceType.InMsgs.end(); I++) // Input Messages + { + Task->MsgTypes[*I].Inputs.push_back(devTypIdx); + } + for(std::vector::const_iterator O=DeviceType.OuMsgs.begin(); + O!=DeviceType.OuMsgs.end(); O++) // Output Messages + { + Task->MsgTypes[*O].Outputs.push_back(devTypIdx); + } + return SUCCESS; +} + +/*============================================================================== + * ClearTask: Removes all the devices from a task + *============================================================================*/ +unsigned AddressBook::ClearTask(const std::string &TaskName) +{ + // The easiest way to do this is simply to copy the data to be saved into + // a TaskData_t object, remove the task, then re-add it with all the device + // data removed. + TaskData_t cTask; + unsigned err = SUCCESS; + if ((err = GetTask(TaskName, cTask)) != SUCCESS) return err; + cTask.DeviceCountLd = 0; + cTask.ExternalCountLd = 0; + cTask.SupervisorCount = 0; + if ((err = DelTask(TaskName)) != SUCCESS) return err; + return AddTask(TaskName, cTask); +} + +/*============================================================================== + * ListTask: Populate a vector with all of the names of loaded tasks + *============================================================================*/ +unsigned AddressBook::ListTask(std::vector &Tasks) +{ + // Enumerate the Task List. + for(TaskMap_t::iterator T=TaskMap.begin();T!=TaskMap.end();T++) + { + Tasks.push_back(T->second->Name); + } + return SUCCESS; +} + +/*============================================================================== + * GetTask: Get a task by name + *============================================================================*/ +unsigned AddressBook::GetTask(const std::string &TaskName, TaskData_t &Task) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + //throw("Task Does Not Exist"); + return ERR_TASK_NOT_FOUND; + } + + Task.Name = TRec->Name; + Task.Path = TRec->Path; + Task.XML = TRec->XML; + Task.ExecutablePath = TRec->ExecPath; + Task.State = TRec->State; + Task.DeviceCount = TRec->DevCntMax; + Task.DeviceCountLd = TRec->DevCnt; + Task.ExternalCount = TRec->ExtCntMax; + Task.ExternalCountLd = TRec->ExtCnt; + Task.SupervisorCount = TRec->SupCnt; + + + //Clear the copied task's vectors just in case this is a re-used TaskData + Task.DeviceTypes.clear(); + Task.MessageTypes.clear(); + Task.AttributeTypes.clear(); + + + // Copy MessageType strings + for(std::vector::const_iterator M=TRec->MsgTypes.begin(); + M!=TRec->MsgTypes.end(); M++) + { + Task.MessageTypes.push_back(M->Name); + } + + // Copy DeviceType strings + for(std::vector::const_iterator D=TRec->DevTypes.begin(); + D!=TRec->DevTypes.end(); D++) + { + Task.DeviceTypes.push_back(D->first); + } + + // Copy AttributeType strings + for(std::vector::const_iterator A=TRec->AttrTypes.begin(); + A!=TRec->AttrTypes.end(); A++) + { + Task.AttributeTypes.push_back(A->first); + } + + return SUCCESS; +} + +/*============================================================================== + * DelTask: Delete the named task + *============================================================================*/ +unsigned AddressBook::DelTask(const std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + //throw("Task Does Not Exist"); + return ERR_TASK_NOT_FOUND; + } + + // Erase it + delete TRec; + TaskMap.erase(TaskName); + + return SUCCESS; +} + +/*============================================================================== + * TaskState: Get the state of the task + *============================================================================*/ +TaskState_t AddressBook::TaskState(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + //throw("Task Does Not Exist"); + return static_cast(Unknown); + } + + return TRec->State; +} + +/*============================================================================== + * TaskState: Set the state of the task + *============================================================================*/ +unsigned AddressBook::TaskState(std::string &TaskName, TaskState_t State) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + //throw("Task Does Not Exist"); + return ERR_TASK_NOT_FOUND; + } + + TRec->State = State; + + return SUCCESS; +} + +/*============================================================================== + * TaskExecPath: Get the path to the executables for the task + *============================================================================*/ +std::string AddressBook::TaskExecPath(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + //throw("Task Does Not Exist"); + return ""; + } + + return TRec->ExecPath; +} + +/*============================================================================== + * TaskExecPath: Set the path to the executables for the task + *============================================================================*/ +unsigned AddressBook::TaskExecPath(std::string &TaskName, std::string &NewPath) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + TRec->ExecPath = NewPath; + return SUCCESS; +} + +/*============================================================================== + * TaskValid: Indicates whether the Task's data is valid + *============================================================================*/ +bool AddressBook::TaskValid(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(false); + } + + return TRec->TaskValid; +} + +/*============================================================================== + * TaskMapValid: Indicates whether the Task's mappings are valid + *============================================================================*/ +bool AddressBook::TaskMapValid(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(false); + } + + return TRec->MapValid; +} + +/*============================================================================== + * TaskLinkValid: Indicates whether the Task's linkage is valid + *============================================================================*/ +bool AddressBook::TaskLinkValid(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(false); + } + + return TRec->LinkValid; +} + + +/*============================================================================== + * RebuildTask: Rebuild the Task's MessageType/DeviceType maps + *============================================================================*/ +unsigned AddressBook::RebuildTask(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + // Rebuild MessageType map + TRec->MsgTypeMap.clear(); + for(std::vector::iterator M=TRec->MsgTypes.begin(); + M!=TRec->MsgTypes.end(); M++) + { + M->Inputs.clear(); // Clear the Input vector data. + M->Outputs.clear(); // Clear the Output vector data. + TRec->MsgTypeMap.insert(IdxMap_t::value_type(M->Name, (M-TRec->MsgTypes.begin()))); + } + + //Rebuild DeviceType Map and links to MessageType - leave the contents of the Device Vector alone! + TRec->DevTypeMap.clear(); + for(std::vector::iterator D=TRec->DevTypes.begin(); + D!=TRec->DevTypes.end(); D++) + { + TRec->DevTypeMap.insert(IdxMap_t::value_type(D->first.Name, (D-TRec->DevTypes.begin()))); + + // Cross-ref to Message Types. + for(std::vector::iterator I=D->first.InMsgs.begin(); + I!=D->first.InMsgs.end(); I++) // Input Messages + { + TRec->MsgTypes[*I].Inputs.push_back(static_cast(D-TRec->DevTypes.begin())); + } + for(std::vector::iterator O=D->first.OuMsgs.begin(); + O!=D->first.OuMsgs.end(); O++) // Output Messages + { + TRec->MsgTypes[*O].Outputs.push_back(static_cast(D-TRec->DevTypes.begin())); + } + } + + //Rebuild AttributeType map - leave the contents of the Device Vector alone! + TRec->AttrTypeMap.clear(); + for(std::vector::iterator A=TRec->AttrTypes.begin(); + A!=TRec->AttrTypes.end(); A++) + { + TRec->AttrTypeMap.insert(IdxMap_t::value_type(A->first, (A-TRec->AttrTypes.begin()))); + } + + return SUCCESS; +} + +/*============================================================================== + * BuildMaps: Build Task Maps + *============================================================================*/ +unsigned AddressBook::BuildMaps(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(TRec->MapValid || TRec->NameMap.size() > 0 + || TRec->ExtCon.size() > 0) ClearMap(TRec); // Existing map, clear it + + + // Map all of the Devices + for(std::vector::iterator DRec=TRec->Devices.begin(); + DRec!=TRec->Devices.end(); DRec++) + { + MapDevice(TRec, &(*DRec)); + } + + // Map all of the Externals + for(std::vector::iterator ERec=TRec->Externals.begin(); + ERec!=TRec->Externals.end(); ERec++) + { + MapDevice(TRec, &(*ERec)); + } + + // Map all of the Supervisors + for(std::vector::iterator SRec=TRec->Supervisors.begin(); + SRec!=TRec->Supervisors.end(); SRec++) + { + // Add the supervisor to the correct DeviceType list. + TRec->DevTypes[SRec->DeviceType].second.push_back(&(*SRec)); + } + + TRec->MapValid = true; // added 18 July 2019 ADR update the map status + + return SUCCESS; +} + +/*============================================================================== + * BuildLink: Build Task linkage + *============================================================================*/ +unsigned AddressBook::BuildLink(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(TRec->LinkValid || TRec->AddrMap.size() > 0) ClearLink(TRec); // Existing link, clear it + + // Link all of the Devices + for(std::vector::iterator DRec=TRec->Devices.begin(); + DRec!=TRec->Devices.end(); DRec++) + { + LinkDevice(TRec, &(*DRec)); + } + + // Link all of the Externals + for(std::vector::iterator ERec=TRec->Externals.begin(); + ERec!=TRec->Externals.end(); ERec++) + { + TRec->AddrMap.insert(AddrMap_t::value_type(ERec->Address, &(*ERec))); + } + + // Link all of the Supervisors + for(std::vector::iterator SRec=TRec->Supervisors.begin(); + SRec!=TRec->Supervisors.end(); SRec++) + { + TRec->AddrMap.insert(AddrMap_t::value_type(SRec->Address, &(*SRec))); + } + + TRec->LinkValid = true; // added 18 July 2019 ADR update the link status + + return SUCCESS; +} + + +//============================================================================== +//Device Addition +unsigned AddressBook::AddDevice(std::string &TaskName, Record_t &DevRec, bool Validate) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + // DebugPrint("No such task: %s\n", TaskName.c_str()); + return(ERR_TASK_NOT_FOUND); + } + + Record_t *DRec; + + if (Validate) // Check that the device does not already exist + { // and that the indices are valid. + unsigned Ret = ValidateDevice(TRec, DevRec); + // DebugPrint("Device validation %s\n", (Ret ? "failed" : "succeeded")); + if(Ret) return Ret; + } + + if ((DevRec.RecordType == Device) || (DevRec.RecordType == DeviceExt)) + { + // Add a Device + // DebugPrint("Ordinary device being added\n"); + CheckVector(TRec, TRec->Devices); // Sanity check for reallocation. + + TRec->Devices.push_back(DevRec); // Add Dev to task. + TRec->DevCnt++; + DRec = &TRec->Devices.back(); + + LinkDevice(TRec, DRec); // Add Device to name map & supervisor list. + MapDevice(TRec, DRec); // Add dev to other maps & lists. + + } else if (DevRec.RecordType == External) { + // Add an External + // DebugPrint("External device being added\n"); + CheckVector(TRec, TRec->Externals); // Sanity check for reallocation + + TRec->Externals.push_back(DevRec); + TRec->ExtCnt++; + DRec = &TRec->Externals.back(); + + TRec->AddrMap.insert(AddrMap_t::value_type(DRec->Address, DRec)); + MapDevice(TRec, DRec); // Add dev to other maps & lists. + + } else if (DevRec.RecordType == Supervisor) { + // Add a Supervisor + // DebugPrint("Supervisor device being added\n"); + CheckVector(TRec, TRec->Supervisors); // Sanity check for reallocation. + + TRec->Supervisors.push_back(DevRec); + TRec->SupCnt++; + DRec = &TRec->Supervisors.back(); + + TRec->AddrMap.insert(AddrMap_t::value_type(DRec->Address, DRec)); + + // Add the supervisor to the correct DeviceType list. + TRec->DevTypes[DRec->DeviceType].second.push_back(DRec); + + SupMap_t::iterator SSearch = TRec->SupMap.find(DRec->Address); + if (SSearch == TRec->SupMap.end()) + { //Supervisor is NOT in the map yet. + TRec->SupMap.insert(SupMap_t::value_type(DRec->Address, + RecordVect_t())); + } + } + // added 18 July 2019 ADR - if Map and Link were previously invalidated + // rebuild everything + // + // Reverted by GMB as this potentially means heafty rebuilding + // when futzing with the data structure - the correct course of + // action is to check the task validity after adding devices and + // rebuilding the link and map then if required. + // + //unsigned err; + //if (!TRec->MapValid && ((err = BuildMaps(TRec->Name)) != SUCCESS)) return err; + //if (!TRec->LinkValid && ((err = BuildLink(TRec->Name)) != SUCCESS)) return err; + + return SUCCESS; +} + + +/*============================================================================== + * UpdateDevice: Update a device with a new address and supervisor. + * This implicitly marks the Linkage as invalid. + *============================================================================*/ +unsigned AddressBook::UpdateDevice(std::string &TaskName, DeviceData_t &Data) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + // Check that the Device Name exists + NameMap_t::iterator DSearch = TRec->NameMap.find(Data.Name); + if (DSearch == TRec->NameMap.end()) { + return ERR_DEVICE_NOT_FOUND; + } + Record_t *DRec = DSearch->second; + + TRec->LinkValid = false; // Mark the Task linkage as dirty + DRec->Address = Data.Address; // Update the Device Address + DRec->Supervisor = Data.Supervisor; // Update the Device Supervisor + return SUCCESS; +} + +/*============================================================================== + * GetDeviceCount: Get the number of devices reserved in the named task + *============================================================================*/ +long AddressBook::GetDeviceCount(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_BAD_COUNT); + } + + return static_cast(TRec->DevCntMax); +} + +/*============================================================================== + * GetLoadedDeviceCount: Get the number of devices loaded in the named task + *============================================================================*/ +long AddressBook::GetLoadedDeviceCount(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_BAD_COUNT); + } + + return static_cast(TRec->DevCnt); +} + +/*============================================================================== + * GetExternalCount: Get the number of externals reserved in the named task + *============================================================================*/ +long AddressBook::GetExternalCount(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_BAD_COUNT); + } + + return static_cast(TRec->ExtCntMax); +} + +/*============================================================================== + * GetLoadedExternalCount: Get the number of externals loaded in the named task + *============================================================================*/ +long AddressBook::GetLoadedExternalCount(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_BAD_COUNT); + } + + return static_cast(TRec->ExtCnt); +} + +/*============================================================================== + * GetSupervisorCount: Get the number of supervisors allocated to the task + *============================================================================*/ +int AddressBook::GetSupervisorCount(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_BAD_COUNT); + } + + return static_cast(TRec->SupCnt); +} + +/*============================================================================== + * GetSupervisorCount: Get the number of supervisors allocated to the task + *============================================================================*/ +int AddressBook::GetMappedSupervisorCount(std::string &TaskName) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_BAD_COUNT); + } + + return TRec->SupMap.size(); +} + + +//============================================================================== +//Device Queries + +/*============================================================================== + * FindDevice: Find a device by Address. + * Gives a Pointer to Const Device Record + *============================================================================*/ +unsigned AddressBook::FindDevice(std::string &TaskName, SymAddr_t Address, const Record_t* &DRec) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + AddrMap_t::iterator DSearch = TRec->AddrMap.find(Address); // Find the Device + if (DSearch == TRec->AddrMap.end()) { + return(ERR_DEVICE_NOT_FOUND); + } + + DRec = &(*DSearch->second); + return SUCCESS; +} + + +/*============================================================================== + * FindDevice: Find a device by Name. + * Gives a Pointer to Const Device Record + *============================================================================*/ +unsigned AddressBook::FindDevice(std::string &TaskName, std::string &Name, const Record_t* &DRec) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + NameMap_t::iterator DSearch = TRec->NameMap.find(Name); // Find the Device + if (DSearch == TRec->NameMap.end()) { + return(ERR_DEVICE_NOT_FOUND); + } + + DRec = &(*DSearch->second); + return SUCCESS; +} + + +/*============================================================================== + * FindBySuper: Find a vector of devices supervised by Supervisor. + * Gives a Pointer to a const Vector of Pointers to const Device + * Records. + *============================================================================*/ +unsigned AddressBook::FindBySuper(std::string &TaskName, SymAddr_t Supervisor, const RecordVect_t* &Records) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + SupMap_t::iterator SSearch = TRec->SupMap.find(Supervisor); // Find the Supervisor + if (SSearch == TRec->SupMap.end()) { + return(ERR_DEVICE_NOT_FOUND); + } + + Records = &SSearch->second; + return SUCCESS; +} + +unsigned AddressBook::FindByType(std::string &TaskName, std::string Type, const RecordVect_t* &Records) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + IdxMap_t::iterator TSearch = TRec->DevTypeMap.find(Type); // Find the Index + if (TSearch == TRec->DevTypeMap.end()) { + return(ERR_DEVICE_NOT_FOUND); + } + + Records = &(TRec->DevTypes[TSearch->second].second); + + return SUCCESS; +} + +unsigned AddressBook::FindByAttribute(std::string &TaskName, std::string Attribute, const RecordVect_t* &Records) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + IdxMap_t::iterator ASearch = TRec->AttrTypeMap.find(Attribute); // Find the Index + if (ASearch == TRec->AttrTypeMap.end()) { + return(ERR_DEVICE_NOT_FOUND); + } + + Records = &(TRec->AttrTypes[ASearch->second].second); + + return SUCCESS; +} + +unsigned AddressBook::FindByInMsg(std::string &TaskName, std::string Msg, const RecordVect_t* &Records) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + return SUCCESS; +} + +unsigned AddressBook::FindByOuMsg(std::string &TaskName, std::string Msg, const RecordVect_t* &Records) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + return SUCCESS; +} + +unsigned AddressBook::GetDevices(std::string &TaskName, const std::vector* &Records) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + Records = &(TRec->Devices); + + return SUCCESS; +} + +unsigned AddressBook::GetExternals(std::string &TaskName, const std::vector* &Records) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + Records = &(TRec->Externals); + + return SUCCESS; +} + +unsigned AddressBook::GetSupervisors(std::string &TaskName, const std::vector* &Records) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + Records = &(TRec->Supervisors); + + return SUCCESS; +} + +unsigned AddressBook::GetExtCon(std::string &TaskName, const RecordVect_t* &Records) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + if(!(TRec->TaskValid && TRec->MapValid && TRec->LinkValid)) // Return NotFound if dirty + { + return ERR_INVALID_MAP; + } + + Records = &(TRec->ExtCon); + + return SUCCESS; +} + + + + +//============================================================================== +//Private Methods + +/*============================================================================== + * FindTask: Return a pointer to the named task. + *============================================================================*/ +TaskRecord_t * AddressBook::FindTask(const std::string &TaskName) +{ + // Check that the task exists. + TaskMap_t::iterator TSearch = TaskMap.find(TaskName); + if (TSearch == TaskMap.end()) { + return(PNULL); + } + + return TSearch->second; +} + + +unsigned AddressBook::MapDevice(TaskRecord_t *TRec, Record_t *DRec) +{ + // Add device to name map + TRec->NameMap.insert(NameMap_t::value_type(DRec->Name, DRec)); + + // Add the device to the correct DeviceType list. + TRec->DevTypes[DRec->DeviceType].second.push_back(DRec); + + if(DRec->RecordType == DeviceExt) // Device has an external conn + { + TRec->ExtCon.push_back(DRec); // Add it to the list of such devices. + } + + // Add the device to the correct attribute list + if(DRec->Attribute > -1) + { + TRec->AttrTypes[static_cast(DRec->Attribute)].second.push_back(DRec); + } + + return SUCCESS; +} + +unsigned AddressBook::LinkDevice(TaskRecord_t *TRec, Record_t *DRec) +{ + // Add Device to Address map. + TRec->AddrMap.insert(AddrMap_t::value_type(DRec->Address, DRec)); + + // Add the device to the correct Supervisor list. + // Supervisors may be loaded after devices, may need to build the map. + SupMap_t::iterator SSearch = TRec->SupMap.find(DRec->Supervisor); + if (SSearch == TRec->SupMap.end()) { //Supervisor is NOT in the map yet. + std::pair LastVal; // Have to do this because C++98 does not like initialiser lists... + LastVal = TRec->SupMap.insert(SupMap_t::value_type(DRec->Supervisor, RecordVect_t())); + LastVal.first->second.push_back(DRec); // RecordVect_t({DRec}) in the insert would be neater and not need the pair. + + } else { //Supervisor is already in the map. + SSearch->second.push_back(DRec); + } + + return SUCCESS; +} + + +/*============================================================================== + * ValidateTask: Check that the task has a valid vector of DeviceTypes. + *============================================================================*/ +unsigned AddressBook::ValidateTask(TaskData_t &Data) +{ + for(std::vector::const_iterator D=Data.DeviceTypes.begin(); + D!=Data.DeviceTypes.end(); D++) + { + if (unsigned retVal = ValidateDeviceType(*D, Data.MessageTypes.size())) + return retVal; + } + + return SUCCESS; +} + +/*============================================================================== + * ValidateDeviceType: Check that DeviceType Message indices are valid and not + * out of range. + * Added and separated from ValidateTask 5 July 2019 ADR + *============================================================================*/ +unsigned AddressBook::ValidateDeviceType(const DevTypeRecord_t& DevTypRec, unsigned MaxIdx) +{ + for(std::vector::const_iterator I=DevTypRec.InMsgs.begin(); + I!=DevTypRec.InMsgs.end(); I++) + { + if(*I >= MaxIdx) + { + return(ERR_INVALID_MESSAGE_TYPE); + } + } + + // changed to iterate over OuMsgs (was InMsgs) 5 July 2019 ADR + for(std::vector::const_iterator O=DevTypRec.OuMsgs.begin(); + O!=DevTypRec.OuMsgs.end(); O++) + { + if(*O >= MaxIdx) + { + return(ERR_INVALID_MESSAGE_TYPE); + } + } + return 0; +} + + +/*============================================================================== + * ValidateDevice: Check that the device does not already exist in the name map + * and that indices in the Record are not out of range. + *============================================================================*/ +unsigned AddressBook::ValidateDevice(TaskRecord_t *TRec, Record_t &DevRec) +{ + // Check that the device does not already exist in the maps + AddrMap_t::const_iterator DASearch = TRec->AddrMap.find(DevRec.Address); + if (DASearch != TRec->AddrMap.end()) { + // DebugPrint("Device address %llu already exists\n", DevRec.Address); + return(ERR_DEVICE_ADDR_USED); + } + + NameMap_t::const_iterator DNSearch = TRec->NameMap.find(DevRec.Name); + if (DNSearch != TRec->NameMap.end()) { + // DebugPrint("Device name %s already exists\n", DevRec.Name.c_str()); + return(ERR_DEVICENAME_USED); + } + + // Check that the indices are valid BEFORE adding the Device. + if (DevRec.DeviceType >= TRec->DevTypes.size()) { + // DebugPrint("Device type %u does not exist\n", DevRec.DeviceType); + return(ERR_INVALID_DEVTYPE); + } + + if (DevRec.Attribute >= static_cast(TRec->AttrTypes.size())) { + // DebugPrint("Device attribute type %u does not exist\n", DevRec.Attribute); + return(ERR_INVALID_ATTRIBUTE); + } + + return SUCCESS; // Validation Successful +} + +/*============================================================================== + * CheckVector: Check that adding a Record to the vector won't cause a + * reallocation as this would silently invalidate all of the maps. + * If the vector is at capacity, increase it's size, clear the task + * linkage & mappings and mark both as dirty. + * + * As the Record vectors are pre-sized based on what should be in + * the task plus one element, there should never be a reallocation. + *============================================================================*/ +unsigned AddressBook::CheckVector(TaskRecord_t *TRec, std::vector &Vect) +{ + if(Vect.size() == Vect.capacity()) + { + Vect.reserve(static_cast(Vect.capacity()*1.25)); + ClearLink(TRec); + ClearMap(TRec); + return ERR_INVALID_MAP; + } + return SUCCESS; +} + + +/*============================================================================== + * ClearMap: Clear the Device to DeviceType/Attribute/(Message) Type links + * and mark the linkage as dirty. Also clears the Name>Record map + * and list of records with external connections. + *============================================================================*/ +unsigned AddressBook::ClearMap(TaskRecord_t *TRec) +{ + TRec->MapValid = false; // Mark the map as dirty. + TRec->NameMap.clear(); // Clear the Name map + TRec->ExtCon.clear(); // Clear External Connections List. + + // Clear DevType->DeviceRecord vectors + for(std::vector::iterator D=TRec->DevTypes.begin(); + D!=TRec->DevTypes.end();D++) + { + D->second.clear(); + } + + // Clear Attribute->DeviceRecord vectors + for(std::vector::iterator A=TRec->AttrTypes.begin(); + A!=TRec->AttrTypes.end();A++) + { + A->second.clear(); + } + + return SUCCESS; +} + + +/*============================================================================== + * ClearLink: Clear the Address>Record map and the Supervisor>Device links. + * Also marks the linkage as dirty. + *============================================================================*/ +unsigned AddressBook::ClearLink(TaskRecord_t *TRec) +{ + TRec->LinkValid = false; // Mark the linkage as dirty. + TRec->AddrMap.clear(); // Clear the Addres>DeviceRecord map. + + //Clear the Device Record vectors for each supervisor. + for(SupMap_t::iterator S=TRec->SupMap.begin();S!=TRec->SupMap.end();S++) + { + S->second.clear(); + } + + return SUCCESS; +} + + +//============================================================================== +//Integrity Checks +unsigned AddressBook::IntegCheck(void) +{ + std::vector Temp; + return IntegCheck(Temp); +} + +unsigned AddressBook::IntegCheck(std::vector &TaskIntegs) +{ + unsigned TInteg, Ret = 0; + + for(TaskMap_t::const_iterator T=TaskMap.begin(); + T!=TaskMap.end();T++) + { + TInteg = T->second->Integrity(false); + TaskIntegs.push_back(TInteg); + if(TInteg) Ret++; + } + + return Ret; +} + +unsigned AddressBook::IntegTask(std::string &TaskName, bool Verbose, FILE * fp) +{ + TaskRecord_t *TRec = FindTask(TaskName); + if(TRec == PNULL) + { + return(ERR_TASK_NOT_FOUND); + } + + return TRec->Integrity(Verbose, fp); +} + + + +//============================================================================== +//Dumps + +void AddressBook::Dump(std::string &Name) +{ + Dump(stdout, Name); +} + +void AddressBook::Dump(FILE * fp, std::string Name) +{ + fprintf(fp,"AddressBook+++++++++++++++++++++++++++++++++\n"); + fprintf(fp,"AddressBookDerived (this derived process) : %s\n",AddressBookDerived.c_str()); + + if(Name == std::string("")) // Dump high-level task data. + { + fprintf(fp,"Total number of tasks: %lu:\n", TaskMap.size()); + for(TaskMap_t::iterator T=TaskMap.begin(); + T!=TaskMap.end();T++) + { + TaskRecord_t *TRec = T->second; + fprintf(fp,"Task %ld: Key: %s At: %" PTR_FMT "\n", + static_cast(std::distance(TaskMap.begin(), T)), + T->first.c_str(), reinterpret_cast(TRec)); + fprintf(fp,"\tName: %s\n", TRec->Name.c_str()); + fprintf(fp,"\tPath: %s\n", TRec->Path.c_str()); + fprintf(fp,"\tXML: %s\n", TRec->XML.c_str()); + fprintf(fp,"\tExecPath: %s\n", TRec->ExecPath.c_str()); + fprintf(fp,"\tExternal Count: %ld\n", TRec->ExtCntMax); + fprintf(fp,"\tDevice Count: %ld\n", TRec->DevCntMax); + fprintf(fp,"\tState: %d\n", TRec->State); + fprintf(fp,"\tAllocated Supervisors: %ld\n", TRec->SupCnt); + fprintf(fp,"\tLoaded Externals: %ld\n", TRec->ExtCnt); + fprintf(fp,"\tLoaded Devices: %ld\n", TRec->DevCnt); + } + } else { // Dump task-specific data. + // Check that the task exists. + TaskMap_t::const_iterator Search = TaskMap.find(Name); + if (Search == TaskMap.end()) { + fprintf(fp,"ERROR: Task %s not found.\n", Name.c_str()); + } else { + TaskRecord_t *TRec = Search->second; + + //Dump Task Data + fprintf(fp,"Task: %s at %" PTR_FMT "\n", Search->first.c_str(), reinterpret_cast(TRec)); + fprintf(fp,"\tPath: %s\n", TRec->Path.c_str()); + fprintf(fp,"\tExecPath: %s\n", TRec->ExecPath.c_str()); + fprintf(fp,"\tExternal Count: %ld\n", TRec->ExtCntMax); + fprintf(fp,"\tDevice Count: %ld\n", TRec->DevCntMax); + fprintf(fp,"\tState: %d\tTaskValid: %d\tMap Valid: %d\tLink Valid: %d\n", + TRec->State, TRec->TaskValid, TRec->MapValid, TRec->LinkValid); + + //Dump Message Types + fprintf(fp,"\tMessage Types:\t%lu\n", static_cast(TRec->MsgTypes.size())); + fprintf(fp,"\t\tIdx\tName\tMapIdx\tMapName\tDTypeI\tDTypeO\n"); + for(std::vector::const_iterator M + =TRec->MsgTypes.begin();M!=TRec->MsgTypes.end();M++) + { + fprintf(fp,"\t\t%ld\t%s\t", static_cast(M-TRec->MsgTypes.begin()), M->Name.c_str()); + + IdxMap_t::const_iterator MSearch = TRec->MsgTypeMap.find(M->Name); + if (MSearch == TRec->MsgTypeMap.end()) { + fprintf(fp,"Not Mapped\t"); + } else { + fprintf(fp,"%d\t%s\t", MSearch->second, + TRec->MsgTypes[MSearch->second].Name.c_str()); + } + + for(std::vector::const_iterator I= + M->Inputs.begin(); I!=M->Inputs.end(); I++) + { // Input Messages + fprintf(fp,"%d,",*I); + } + fprintf(fp,"\t"); + + for(std::vector::const_iterator O= + M->Outputs.begin();O!=M->Outputs.end(); O++) + { // Output Messages + fprintf(fp,"%d,",*O); + } + fprintf(fp,"\n"); + } + fprintf(fp,"\n"); + + //Dump Device Types + fprintf(fp,"\tDevice Types:\t%lu\n", static_cast(TRec->DevTypes.size())); + fprintf(fp,"\t\tIdx\tName\tMapIdx\tMapName\tDevCnt\tInMsgs\tOuMsgs\n"); + for(std::vector::const_iterator D + =TRec->DevTypes.begin();D!=TRec->DevTypes.end();D++) + { + fprintf(fp,"\t\t%ld\t%s\t", static_cast(D-TRec->DevTypes.begin()), D->first.Name.c_str()); + + //Print the DevTypeMap mapping + IdxMap_t::const_iterator DSearch = TRec->DevTypeMap.find(D->first.Name); + if (DSearch == TRec->DevTypeMap.end()) { + fprintf(fp,"Not Mapped\t"); + } else { + fprintf(fp,"%d\t%s\t", DSearch->second, + TRec->DevTypes[DSearch->second].first.Name.c_str()); + } + + //Print the number of devices of this type. + fprintf(fp,"%lu\t", static_cast(D->second.size())); + + //Print the Input Msg Indices + for(std::vector::const_iterator I + =D->first.InMsgs.begin();I!=D->first.InMsgs.end();I++) + { + fprintf(fp,"%d,", *I); + } + fprintf(fp,"\t"); + + //Print the Output Msg Indices + for(std::vector::const_iterator O + =D->first.OuMsgs.begin();O!=D->first.OuMsgs.end();O++) + { + fprintf(fp,"%d,", *O); + } + fprintf(fp,"\n"); + + } + fprintf(fp,"\n"); + + //Dump Attribute Types + fprintf(fp,"\tAttribute Types:\t%lu\n", static_cast(TRec->AttrTypes.size())); + if(TRec->AttrTypes.size()>0) + { + fprintf(fp,"\t\tIdx\tName\tMapIdx\tMapName\tDevCnt\n"); + for(std::vector::const_iterator A + =TRec->AttrTypes.begin();A!=TRec->AttrTypes.end();A++) + { + fprintf(fp,"\t\t%ld\t%s\t", static_cast(A-TRec->AttrTypes.begin()), + A->first.c_str()); + + IdxMap_t::const_iterator ASearch = TRec->AttrTypeMap.find(A->first); + if (ASearch == TRec->AttrTypeMap.end()) { + fprintf(fp,"Not Mapped\t"); + } else { + fprintf(fp,"%d\t%s\t", ASearch->second, + TRec->AttrTypes[ASearch->second].first.c_str()); + } + + //Print the number of devices with this attribute. + fprintf(fp,"%ld\n", static_cast(A->second.size())); + } + fprintf(fp,"\n"); + } + + // Dump allocated Supervisors + fprintf(fp,"\tAllocated Supervisors: %ld\n", TRec->SupCnt); + if(TRec->SupCnt>0) + { + fprintf(fp,"\t\tIdx\tAddress\tRank\tDev Count\n"); + for(std::vector::const_iterator R + =TRec->Supervisors.begin();R!=TRec->Supervisors.end();R++) + { + //TODO: Write the map search to get count of devices for + // a supervisor. + fprintf(fp,"\t\t%ld\t%" SYMA_FMT "\t%lu\t%d\n", + static_cast(R-TRec->Supervisors.begin()), + R->Address, R->Rank, 0); + } + fprintf(fp,"\n"); + } + + // Dump loaded Externals + fprintf(fp,"\tLoaded Externals: %ld\n", TRec->ExtCnt); + if(TRec->ExtCnt>0) + { + fprintf(fp,"\t\tIdx\tName\tAddress\n"); + for(std::vector::const_iterator R + =TRec->Externals.begin();R!=TRec->Externals.end();R++) + { + fprintf(fp,"\t\t%ld\t%s\t%" SYMA_FMT "\n", + static_cast(R-TRec->Externals.begin()), + R->Name.c_str(), R->Address); + } + fprintf(fp,"\n"); + } + + + // Dump loaded Devices + fprintf(fp,"\tLoaded Devices: %ld\n", TRec->DevCnt); + if(TRec->DevCnt>0) + { + fprintf(fp,"\t\tIdx\tName\tAddress\t\tSupervisor\n"); + for(std::vector::const_iterator R + =TRec->Devices.begin();R!=TRec->Devices.end();R++) + { + fprintf(fp,"\t\t%ld\t%s\t%" SYMA_FMT "\t%" SYMA_FMT "\n", + static_cast(R-TRec->Devices.begin()), + R->Name.c_str(), R->Address, R->Supervisor); + } + } + } + } + + fprintf(fp,"AddressBook_--------------------------------\n"); + fflush(fp); +} +} /* namespace AddressBook */ diff --git a/Source/NameServer/AddressBook/AddressBook.hpp b/Source/NameServer/AddressBook/AddressBook.hpp new file mode 100644 index 00000000..46eae70a --- /dev/null +++ b/Source/NameServer/AddressBook/AddressBook.hpp @@ -0,0 +1,166 @@ +/*============================================================================== + * AddressBook: A back-end implementation for the POETS sbase & Nameserver + * + * Tasks can be *mapped* and *linked*: + * Mapped: Device Records connected to Device (and Message) and Attribute + * types. Device Records with External Connections also listed. + * Linked: Device Records connected to Addresses in Address Map and listed + * in the relevant Supervisor vector. + * + * Linkage is invalidated when/if a Device Record is updated after load. + * Mapping is invalidated if more devices than expected are loaded. + * + * Struct sizing with no Pragma Packing: + * Win 64-Bit Win 32-Bit Mac 64-Bit + * TaskRecord_t 560 324 464 + * Record_t 72 64 52 + * TaskData_t 280 184 216 + * DeviceData_t 56 48 40 + * + * Memory Footprint* 221.7MB 153.2MB 194MB + * *1 task with 1 million devices, 1 supervisor and 1 external. + * + * + * + *============================================================================*/ + +#ifndef AddressBook_H +#define AddressBook_H + +#include "OSFixes.hpp" + +#include "AddressBook_Defs.hpp" +#include "AddressBook_Task.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include + + + +#define MAXSUPERVISORS 16 + +//============================================================================== +namespace AddressBook +{ +typedef std::map TaskMap_t; + +enum ReturnCode_t { ERR_BAD_COUNT = -1, + SUCCESS = 0, + ERR_NONFATAL, + ERR_INVALID_TASK, + ERR_INVALID_DEVTYPE, + ERR_INVALID_DEVICE, + ERR_INVALID_MESSAGE_TYPE, + ERR_INVALID_ATTRIBUTE, + ERR_DEVICE_DATA_MISMATCH, + ERR_TASKNAME_USED, + ERR_DEVICENAME_USED, + ERR_DEVICE_ADDR_USED, + ERR_TASK_NOT_FOUND, + ERR_DEVICE_NOT_FOUND, + ERR_INVALID_MAP, + ERR_INVALID_SUPERVISOR, + ERR_INVALID_STATE + }; + +class AddressBook +{ +public: + AddressBook(std::string d); + ~AddressBook(); + + unsigned GetTaskCount(void); + + // Task Manipulation + unsigned AddTask(const std::string &TaskName, TaskData_t &Data); + unsigned ListTask(std::vector &Tasks); + unsigned GetTask(const std::string &TaskName, TaskData_t &Task); + unsigned DelTask(const std::string &TaskName); + + unsigned AddDeviceType(const std::string &TaskName, const DevTypeRecord_t &DeviceType); // add a new DeviceType + unsigned ClearTask(const std::string &TaskName); // deletes all the devices for a task without removing the task. + + TaskState_t TaskState(std::string &TaskName); // Get the task state + unsigned TaskState(std::string &TaskName, TaskState_t State); // Set the task state + + std::string TaskExecPath(std::string &TaskName); // Get the path of a task + unsigned TaskExecPath(std::string &TaskName, std::string &NewPath); // Set the path of a task + + bool TaskValid(std::string &TaskName); + bool TaskMapValid(std::string &TaskName); + bool TaskLinkValid(std::string &TaskName); + + unsigned RebuildTask(std::string &TaskName); + unsigned BuildMaps(std::string &TaskName); + unsigned BuildLink(std::string &TaskName); + + // Device Manipulation + unsigned AddDevice(std::string &TaskName, Record_t &Device, bool Validate = true); + unsigned UpdateDevice(std::string &TaskName, DeviceData_t &Data); + + // Find a device + unsigned FindDevice(std::string &TaskName, std::string &Name, const Record_t* &DRec); + unsigned FindDevice(std::string &TaskName, SymAddr_t Address, const Record_t* &DRec); + + // Find all devices supervised by X + unsigned FindBySuper(std::string &TaskName, SymAddr_t Supervisor, const RecordVect_t* &Records); + + unsigned FindByType(std::string &TaskName, std::string Type, const RecordVect_t* &Records); + unsigned FindByAttribute(std::string &TaskName, std::string Attribute, const RecordVect_t* &Records); + + unsigned FindByInMsg(std::string &TaskName, std::string Msg, const RecordVect_t* &Records); //TODO + unsigned FindByOuMsg(std::string &TaskName, std::string Msg, const RecordVect_t* &Records); //TODO + + // device getters. Note that a vector is different from a RecordVect_t, + // which is a vector + unsigned GetDevices(std::string &TaskName, const std::vector* &Records); + unsigned GetExternals(std::string &TaskName, const std::vector* &Records); + unsigned GetSupervisors(std::string &TaskName, const std::vector* &Records); + unsigned GetExtCon(std::string &TaskName, const RecordVect_t* &Records); + + // Device Count getters + long GetDeviceCount(std::string &TaskName); + long GetLoadedDeviceCount(std::string &TaskName); + long GetExternalCount(std::string &TaskName); + long GetLoadedExternalCount(std::string &TaskName); + int GetSupervisorCount(std::string &TaskName); + int GetMappedSupervisorCount(std::string &TaskName); + + // Integrity + unsigned IntegCheck(void); // Integrity check of ALL tasks + unsigned IntegCheck(std::vector &TaskIntegs); + unsigned IntegTask(std::string &TaskName, bool Verbose = false, FILE * = stdout); // Ingerity Check a Task by name + //unsigned IntegTask(const TaskRecord_t *TRec, bool Verbose = false, FILE * = stdout); // Ingerity Check a Task by pointer + + // Debugging + void Dump(std::string &Name); + void Dump(FILE * = stdout, std::string Name = ""); + +private: + TaskMap_t TaskMap; + std::string AddressBookDerived; // changed to allow multiple inheritance (from CommonBase) 14 July 2019 ADR + + TaskRecord_t * FindTask(const std::string &TaskName); + + unsigned ValidateDevice(TaskRecord_t *TRec, Record_t &DevRec); + unsigned ValidateDeviceType(const DevTypeRecord_t& DevTypRec, unsigned MaxIdx); + unsigned ValidateTask(TaskData_t &Data); + + unsigned CheckVector(TaskRecord_t *TRec, std::vector &Vect); + + unsigned LinkDevice(TaskRecord_t *TRec, Record_t *DRec); // Add Device to name map & supervisor list. + unsigned MapDevice(TaskRecord_t *TRec, Record_t *DRec); // Add Device to other maps & lists. + + unsigned ClearMap(TaskRecord_t *TRec); + unsigned ClearLink(TaskRecord_t *TRec); + +}; +} /* namespace AddressBook */ + +#endif /* AddressBook_H */ diff --git a/Source/NameServer/AddressBook/AddressBook_Defs.cpp b/Source/NameServer/AddressBook/AddressBook_Defs.cpp new file mode 100644 index 00000000..93e7e13c --- /dev/null +++ b/Source/NameServer/AddressBook/AddressBook_Defs.cpp @@ -0,0 +1,54 @@ +#include "AddressBook_Defs.hpp" + +namespace AddressBook +{ + +// const SymAddr_t INVALID_ADDRESS; + +int DeviceData_t::size() const +{ + int size = 0; + + size += sizeof(SymAddr_t) * 2; + size += Name.size(); + + return size; +} + + +DevTypeRecord_t::DevTypeRecord_t(std::string N) +{ + Name = N; +} + +int DevTypeRecord_t::size() const +{ + int size = 0; + + size += Name.size(); + size += sizeof(MsgIdx) * InMsgs.size(); + size += sizeof(MsgIdx) * OuMsgs.size(); + + return size; +} + + +MsgTypeRecord_t::MsgTypeRecord_t(std::string N) +{ + Name = N; +} + +int MsgTypeRecord_t::size() const +{ + int size = 0; + + size += Name.size(); + size += sizeof(MsgIdx) * Inputs.size(); + size += sizeof(MsgIdx) * Outputs.size(); + + return size; +} + + + +} /* namespace AddressBook */ diff --git a/Source/NameServer/AddressBook/AddressBook_Defs.hpp b/Source/NameServer/AddressBook/AddressBook_Defs.hpp new file mode 100644 index 00000000..839a806d --- /dev/null +++ b/Source/NameServer/AddressBook/AddressBook_Defs.hpp @@ -0,0 +1,59 @@ +#ifndef AddressBook_Defs_H +#define AddressBook_Defs_H + +#include "OSFixes.hpp" + +#include +#include +#include +#include + +namespace AddressBook +{ + +//---------------------------------------- +// Temporary typedefs +typedef uint64_t SymAddr_t; // A 64-bit full-symbolic address + +static const SymAddr_t INVALID_ADDRESS = UINT64_MAX; + +//---------------------------------------- + +enum TaskState_t { Loaded = 0, Linked, Built, Deployed, Init, Running, Finished, Unknown }; + +typedef unsigned DTypeIdx; +typedef int AttrIdx; +typedef unsigned MsgIdx; + + +struct DeviceData_t { + int size() const; // Get the size of the DeviceData + + SymAddr_t Address; // Device's full symbolic address. + SymAddr_t Supervisor; // Full symbolic address of the Device's Supervisor. + std::string Name; // Device's canonical name. +}; + + +struct DevTypeRecord_t { + DevTypeRecord_t(std::string N = ""); + int size() const; // Get the size of the DeviceType Record + + std::string Name; // Device Type canonical name. + std::vector InMsgs; // Vector of Input Message indexes + std::vector OuMsgs; // Vector of Output Message indexes +}; + + + +struct MsgTypeRecord_t { + MsgTypeRecord_t(std::string N = ""); + int size() const; // Get the size of the MsgType Record + + std::string Name; // Message Type Name + std::vector Inputs; // Indicies of DeviceTypes that have this MessageType as an input + std::vector Outputs; // Indicies of DeviceTypes that have this MessageType as an output +}; + +} /* namespace AddressBook */ +#endif /* AddressBook_Defs_H */ diff --git a/Source/NameServer/AddressBook/AddressBook_Record.cpp b/Source/NameServer/AddressBook/AddressBook_Record.cpp new file mode 100644 index 00000000..0bbb5e20 --- /dev/null +++ b/Source/NameServer/AddressBook/AddressBook_Record.cpp @@ -0,0 +1,49 @@ +#include "AddressBook_Record.hpp" + +namespace AddressBook +{ + +/*============================================================================== + * Record_t::Record_t(): Default initialiser for a Record_t. + *============================================================================*/ +Record_t::Record_t() +{ + Attribute = -1; // Set to -1 to ensure that we don't go out of range. +} + +/*============================================================================== + * Record_t::Record_t(): Full initialiser for a Record_t + *============================================================================*/ +Record_t::Record_t(std::string Name, SymAddr_t Addr, uint64_t Super, + DTypeIdx Type, RecordType_t RT, AttrIdx Attr) + : Name(Name) +{ + Address = Addr; + DeviceType = Type; + RecordType = RT; + Attribute = Attr; + Rank = 0; + Supervisor = 0; + if (RecordType == Supervisor) Rank = static_cast(Super); + else Supervisor = static_cast(Super); +} + + +/*============================================================================== + * Record_t::size(): Return the size (in bytes) of the address record. + *============================================================================*/ +int Record_t::size() const +{ + int size = 0; + + size += sizeof(SymAddr_t) * 2; // Address and Supervisor/Rank + size += sizeof(DTypeIdx); // Device Type Index + size += sizeof(AttrIdx); // Attribute Index + size += sizeof(RecordType_t); // Record Type + size += sizeof(char) * Name.size(); // Name + + return size; +} + + +} /* namespace AddressBook */ diff --git a/Source/NameServer/AddressBook/AddressBook_Record.hpp b/Source/NameServer/AddressBook/AddressBook_Record.hpp new file mode 100644 index 00000000..0659e1a0 --- /dev/null +++ b/Source/NameServer/AddressBook/AddressBook_Record.hpp @@ -0,0 +1,39 @@ +#ifndef AddressBook_Record_H +#define AddressBook_Record_H + +#include "AddressBook_Defs.hpp" + +namespace AddressBook +{ +enum RecordType_t { Device = 0, DeviceExt, External, Supervisor }; + +// data contents factored out for serialisation 17 July 2019 ADR +struct RecordData_t +{ + public: + + SymAddr_t Address; // Device's full sym address. + union // Disambiguated by RecordType, which appears at + { // at the end of the struct for packing reasons. + SymAddr_t Supervisor; // Full sym address of the Device's Supervisor. + unsigned long Rank; // OR Supervisor's MPI Rank. + }; + DTypeIdx DeviceType; // Index of the Device's type in task. + AttrIdx Attribute; // Index of the Device's attribute in task. + RecordType_t RecordType; // Class of device represented by the record. +}; + +class Record_t : public RecordData_t +{ + public: + + Record_t(); + Record_t(std::string, SymAddr_t, uint64_t, DTypeIdx, RecordType_t = Device, AttrIdx = -1); + + int size() const; // Size of the record + + std::string Name; // Device's canonical name. +}; + +} /* namespace AddressBook */ +#endif /* AddressBook_Record_H */ diff --git a/Source/NameServer/AddressBook/AddressBook_Task.cpp b/Source/NameServer/AddressBook/AddressBook_Task.cpp new file mode 100644 index 00000000..b8fe21d3 --- /dev/null +++ b/Source/NameServer/AddressBook/AddressBook_Task.cpp @@ -0,0 +1,887 @@ +#include "AddressBook_Task.hpp" + +namespace AddressBook +{ + +/*============================================================================== + * TaskData - used to communicate task data without maps and pointers. + *============================================================================*/ +TaskData_t::TaskData_t() +{ + Name = ""; + Path = ""; + XML = ""; + ExecutablePath = ""; + State = Loaded; + DeviceCount = 0; + DeviceCountLd = 0; + ExternalCount = 0; + ExternalCountLd = 0; + SupervisorCount = 0; + + State = Loaded; +} + +/*============================================================================== + * TaskData_t::TaskData_t(): Full initialiser for a TaskData_t + *============================================================================*/ +TaskData_t::TaskData_t(std::string &N, std::string &P, std::string &X, + std::string &E, TaskState_t S, unsigned long DC, + unsigned long EC) +{ + Name = N; + Path = P; + XML = X; + ExecutablePath = E; + State = Loaded; + DeviceCount = DC; + DeviceCountLd = 0; + ExternalCount = EC; + ExternalCountLd = 0; + SupervisorCount = 0; + + State = S; +} + +/*============================================================================== + * TaskData_t::size(): Return the size (in bytes) of the address record. + *============================================================================*/ +int TaskData_t::size() const +{ + int size = 0; + + size += sizeof(unsigned long)*5; // Size of the 5 longs + size += sizeof(char) * Name.size(); // Size of the name + size += sizeof(char) * Path.size(); // Size of the path + size += sizeof(char) * XML.size(); // Size of the XML Filename + size += sizeof(char) * ExecutablePath.size(); // Size of the exec path + size += sizeof(TaskState_t); + + for(std::vector::const_iterator DT = DeviceTypes.begin(); + DT != DeviceTypes.end(); DT++) // Size of the device types + { + size += DT->size(); + } + + for(std::vector::const_iterator MT = MessageTypes.begin(); + MT != MessageTypes.end(); MT++) // Size of the Message Types + { + size += MT->size(); + } + + for(std::vector::const_iterator AT = AttributeTypes.begin(); + AT != AttributeTypes.end(); AT++) // Size of the Attribute Types + { + size += AT->size(); + } + + return size; +} + +/*============================================================================== + * TaskRecord - stores data about the task in an instance of AddressBook + *============================================================================*/ +TaskRecord_t::TaskRecord_t() +{ + Name = ""; + Path = ""; + XML = ""; + ExecPath = ""; + DevCntMax = 0; + ExtCntMax = 0; + DevCnt = 0; + SupCnt = 0; + ExtCnt = 0; + + State = Loaded; + + TaskValid = true; + MapValid = true; + LinkValid = true; +} + +/*============================================================================== + * TaskRecord_t::TaskRecord_t(): Full initialiser for a TaskRecord_t + *============================================================================*/ +TaskRecord_t::TaskRecord_t(std::string &N, std::string &P, std::string &X, + std::string &E, TaskState_t S, unsigned long DC, + unsigned long EC) +{ + Name = N; + Path = P; + XML = X; + ExecPath = E; + DevCntMax = DC; + ExtCntMax = EC; + DevCnt = 0; + SupCnt = 0; + ExtCnt = 0; + + State = S; + + TaskValid = true; + MapValid = true; + LinkValid = true; +} + + +/*============================================================================== + * TaskRecord_t::Integrity(): Run an integrity check on the entire task. + * + * Verbose: Print lots of information to *fp (stdout by default). + * + * Scours the data structure checking that all of the maps and vectors all + * point to valid data and that there are no invalid indicies or pointers. + * + * This will mark the underlying data structure as dirty if it finds any + * inconsistencies. If RECOVERABLEINTEGRITY is defined, a successful + * integrity check marks the data structure as clean. + * + * When AB_THREADING is defined (by default this is when built with C++11 + * (or newer) AND (C11 (or newer) OR POSIX)), the integrity checks are + * parallelised to reduce the potentially significant runtime of large + * applications. The number of threads is set based on the available + * concurrency, with at least one thread used for each check type (minimum + * 4 threads). Where concurrency is high, 2*concurrency threads are used in + * the following way: + * Devices vector 1*concurrency threads + * DeviceType vectors, etc. 0.5*concurrency threads + * Supervisors vector 0.25*concurrency threads + * Externals vector 0.25*concurrency threads + * + *============================================================================*/ +unsigned TaskRecord_t::Integrity(bool Verbose, FILE * fp) +{ + AB_ULONG ExtConCnt(0); + AB_UNSIGNED MappedSupervisors(0); + + IntegVals_t retVal; + retVal.ret = 0; + retVal.retT = 0; + retVal.retL = 0; + retVal.retM = 0; + + + if (Verbose) fprintf(fp, "Integrity check of %s:\n", Name.c_str()); + + //========================================================================== + // Task checks + + // Device Counts - failing these means the task is broken? + if(Devices.size() != DevCnt) + { + // Device Count mismatch. + if (Verbose) fprintf(fp, "Device Count mismatch: %lu!=%lu\n", + static_cast(Devices.size()), DevCnt); + retVal.ret++; + } + + if(Externals.size() != ExtCnt) + { + // External Count mismatch. + if (Verbose) fprintf(fp, "External Count mismatch: %lu!=%lu\n", + static_cast(Externals.size()), ExtCnt); + retVal.ret++; + } + + if(Supervisors.size() != SupCnt) + { + // Supervisor Count mismatch. + if (Verbose) fprintf(fp, "Supervisor Count mismatch: %lu!=%lu\n", + static_cast(Supervisors.size()), SupCnt); + retVal.ret++; + } + + if(SupMap.size() != SupCnt) + { + // Supervisor Count-SupMap size mismatch. + if (Verbose) fprintf(fp, "Supervisor Count<>SupMap size mismatch: %lu!=%lu\n", + static_cast(SupMap.size()), SupCnt); + retVal.ret++; + } + + +#ifdef AB_THREADING + //========================================================================== + // Multi-threaded checks of large structures. Number of threads used scales + // with the number of CPU cores. The checks are read-only so no locks for + // data structure access. Atomic types are used for return values. + unsigned threadCnt = 0, i = 0; + + // Base the scaling off of the available concurrency, with a minimum of 1 + // thread for each check, for a minimum of 4 total threads. Otherwise, + // maximum concurrency is 2* available concurrency. + unsigned int concurrency = std::thread::hardware_concurrency(); + unsigned int halfConcurrency = (concurrency < 2) ? 1 : concurrency / 2; + unsigned int qrtrConcurrency = (concurrency < 4) ? 1 : concurrency / 4; + + // Create a vector of threads of the correct size. + std::vector threads(concurrency + halfConcurrency + + qrtrConcurrency + qrtrConcurrency); + + + //========================================================================== + // Thread(s) for checking DeviceType vectors, etc. + unsigned long dtConcurrency = halfConcurrency; + if (DevTypes.size() < halfConcurrency) // Limit number of threads if we + { // have fewer DeviceTypes than + dtConcurrency = DevTypes.size(); // possible threads. + } + + if (dtConcurrency > 0) + { + unsigned long devTypeSplit = DevTypes.size() / dtConcurrency; + for(i = 0; i < dtConcurrency; i++) + { + // Handle any remainder in the last thread - integ method checks bounds. + unsigned endMul = (i==(dtConcurrency-1)) ? 2 : 1; + threads[threadCnt+i] = std::thread(&TaskRecord_t::IntegDevTypeMap, this, + Verbose, fp, (devTypeSplit * i), + (devTypeSplit * (i+endMul)), + std::ref(retVal)); + } + threadCnt += i; + } + + //========================================================================== + // Thread(s) for checking Devices vector + unsigned long dConcurrency = concurrency; + if (Devices.size() < concurrency) // Limit number of threads if we + { // have fewer Devices than + dConcurrency = Devices.size(); // possible threads. + } + + if (dConcurrency > 0) // account for 0 devices, incase we are called before devices loaded + { + unsigned long long devSplit = Devices.size() / dConcurrency; + for(i = 0; i < dConcurrency; i++) + { + // Handle any remainder in the last thread - integ method checks bounds. + unsigned endMul = (i==(dConcurrency-1)) ? 2 : 1; + threads[threadCnt+i] = std::thread(&TaskRecord_t::IntegDevices, this, + Verbose, fp, (devSplit * i), + (devSplit * (i+endMul)), + std::ref(retVal), + std::ref(ExtConCnt)); + } + threadCnt += i; + } + + //========================================================================== + // Thread(s) for checking Externals vector + unsigned long eConcurrency = qrtrConcurrency; + if (Externals.size() < qrtrConcurrency) // Limit number of threads if we + { // have fewer Externals than + eConcurrency = Externals.size(); // possible threads. + } + + if (eConcurrency > 0) // Account for having no externals + { + unsigned long extSplit = Externals.size() / eConcurrency; + for(i = 0; i < eConcurrency; i++) + { + // Handle any remainder in the last thread - integ method checks bounds. + unsigned endMul = (i==(eConcurrency-1)) ? 2 : 1; + threads[threadCnt+i] = std::thread(&TaskRecord_t::IntegExternals, this, + Verbose, fp, (extSplit * i), + (extSplit * (i+endMul)), + std::ref(retVal)); + } + threadCnt += i; + } + + //========================================================================== + // Thread(s) for checking Supervisors vector. + unsigned long sConcurrency = qrtrConcurrency; + if (Supervisors.size() < qrtrConcurrency) // Limit number of threads if we + { // have fewer Supervisors than + sConcurrency = Supervisors.size(); // possible threads. + } + + if (sConcurrency > 0) // Account for having no supervisors + { + unsigned long superSplit = Supervisors.size() / sConcurrency; + for(i = 0; + i < sConcurrency; + i++) + { + // Handle any remainder in the last thread - integ method checks bounds. + unsigned endMul = (i==(sConcurrency-1)) ? 2 : 1; + threads[threadCnt+i] = std::thread(&TaskRecord_t::IntegSupervisors, this, + Verbose, fp, (superSplit * i), + (superSplit * (i+endMul)), + std::ref(retVal), + std::ref(MappedSupervisors)); + } + threadCnt += i; + } + +#endif + + // Check integrity of MsgType map + for(std::vector::iterator M + =MsgTypes.begin();M!=MsgTypes.end();M++) // Iterate through message type vector + { + unsigned Idx = static_cast(std::distance(MsgTypes.begin(), M)); // Current Index + + IdxMap_t::const_iterator MSearch = MsgTypeMap.find(M->Name); // Find the Msg Name in the map + if (MSearch == MsgTypeMap.end()) { + // Message Type not mapped + if (Verbose) fprintf(fp, "T: Message Type not mapped: %s\n", + M->Name.c_str()); + retVal.retT++; + } else { + if (MsgTypes[MSearch->second].Name != M->Name){ + // Message Type > Index map is broken. + if (Verbose) fprintf(fp, "T: Message Type > Index map is broken: %s\n", + M->Name.c_str()); + retVal.retT++; + } + + if (Idx != MSearch->second) { + // Index mismatch + if (Verbose) fprintf(fp, "T: Index mismatch: %s, %u!=%u\n", + M->Name.c_str(), Idx, MSearch->second); + retVal.retT++; + } + } + } + + // Check integrity of AttributeType map + for(std::vector::iterator A + =AttrTypes.begin();A!=AttrTypes.end();A++) // Iterate through message type vector + { + unsigned Idx = static_cast(std::distance(AttrTypes.begin(), A)); // Current Index + + IdxMap_t::const_iterator ASearch = AttrTypeMap.find(A->first); // Find the Msg Name in the map + if (ASearch == AttrTypeMap.end()) { + // Attribute Type not mapped + if (Verbose) fprintf(fp, "T: Attribute Type not mapped: %s\n", + A->first.c_str()); + retVal.retT++; + } else { + if (AttrTypes[ASearch->second].first != A->first){ + // Attribute Type > Index map is broken. + if (Verbose) fprintf(fp, "T: Attribute > Index map broken: %s!=%s\n", + A->first.c_str(), AttrTypes[ASearch->second].first.c_str()); + retVal.retT++; + } + + if (Idx != ASearch->second) { + // Index mismatch + if (Verbose) fprintf(fp, "T: Attribute Index mismatch: %u!m%u\n", + Idx, ASearch->second); + retVal.retT++; + } + } + } + + + //========================================================================== + // Map checks + + // Map size integrity checks - Re-mapping should fix. + unsigned long totalDevCnt = DevCnt + ExtCnt; + if(NameMap.size() != totalDevCnt) + { + // NameMap Size mismatch - Map broken + if (Verbose) fprintf(fp, "M: NameMap size mismatch: %lu!=%lu\n", + static_cast(NameMap.size()), + totalDevCnt); + retVal.retM++; + } + + + //========================================================================== + // Link checks + + // Link integrity checks - Re-linking should fix. + if(AddrMap.size() != (totalDevCnt + SupCnt)) + { + // AddressMap Size mismatch - Link broken + if (Verbose) fprintf(fp, "L: AddrMap Size mismatch: %lu!=%lu\n", + static_cast(AddrMap.size()), + (DevCnt + SupCnt)); + retVal.retL++; + } + + +#ifdef AB_THREADING + // Wait for all of the threads to finish + for(i = 0; i < threadCnt; i++) + { + threads[i].join(); + } +#else + // If we are not using threading, run all of the (long) integrity checks single-threaded. + + //========================================================================== + // Check integrity of DeviceType map + IntegDevTypeMap(Verbose, fp, 0, DevTypes.size(), retVal); + + //========================================================================== + // Device checks + IntegDevices(Verbose, fp, 0, Devices.size(), retVal, ExtConCnt); // Check ALL devices + + //========================================================================== + // External checks + IntegExternals(Verbose, fp, 0, Externals.size(), retVal); // Check ALL externals + + //========================================================================== + // Supervisor checks + IntegSupervisors(Verbose, fp, 0, Supervisors.size(), retVal, MappedSupervisors); // Check ALL supervisors +#endif + + + //========================================================================== + // Check ExtCon size. + if(ExtCon.size() != ExtConCnt) + { + // External Connection vector size mismatch - Map broken + if (Verbose) fprintf(fp, "M: External Connection Vector size mismatch: %lu!=%lu\n", + static_cast(ExtCon.size()), + static_cast(ExtConCnt)); + retVal.retM++; + } + + //========================================================================== + // Check Supervisor map size + if (MappedSupervisors != SupMap.size()) { + // Supervisor Map size missmatch + if (Verbose) fprintf(fp, "L: Supervisor Size mismatch: %u!=%lu\n", + static_cast(MappedSupervisors), + static_cast(SupMap.size())); + retVal.retL++; + } + + //========================================================================== + // Set dirty flags if appropriate + if (Verbose) fprintf(fp, "\nResults:\n"); + + if (retVal.ret > 0) + { + if (Verbose) fprintf(fp, "\tGeneral Breakage: %d\n", static_cast(retVal.ret)); + } + + + if (retVal.retT > 0) // Task integrity compromised - need to rebuild the task + { + TaskValid = false; + if (Verbose) fprintf(fp, "\tDirty Task: %d\n", static_cast(retVal.retT)); + retVal.ret += retVal.retT; + } +#ifdef RECOVERABLEINTEGRITY + else + { + TaskValid = true; + } +#endif + + if (retVal.retM > 0) // Map integrity compromised - need to rebuild the map + { + MapValid = false; + if (Verbose) fprintf(fp, "\tDirty Map: %d\n", static_cast(retVal.retM)); + retVal.ret += retVal.retM; + } +#ifdef RECOVERABLEINTEGRITY + else + { + MapValid = true; + } +#endif + + if (retVal.retL > 0) // Link integrity compromised - need to rebuild the link + { + LinkValid = false; + if (Verbose) fprintf(fp, "\tDirty Link: %d\n", static_cast(retVal.retL)); + retVal.ret += retVal.retL; + } +#ifdef RECOVERABLEINTEGRITY + else + { + LinkValid = true; + } +#endif + + if (Verbose && (retVal.ret == 0)) fprintf(fp, "\tTask Clean\n"); + + return retVal.ret; +} + + +/*============================================================================== + * TaskRecord_t::IntegDevTypeMap(): Run an integrity check on the device type + * map in the range of DStart-DEnd. + *============================================================================*/ +void TaskRecord_t::IntegDevTypeMap(bool Verbose, FILE * fp, unsigned long DTStart, + unsigned long DTEnd, IntegVals_t &retVal) +{ + for(std::vector::iterator D = DevTypes.begin() + DTStart; + (D != DevTypes.end()) && (D < (DevTypes.begin() + DTEnd)); + D++) // Iterate through device type vector + { + unsigned Idx = static_cast(std::distance(DevTypes.begin(), D)); // Current Index + + IdxMap_t::const_iterator DTSearch = DevTypeMap.find(D->first.Name); // Find the DevType name in the map + if (DTSearch == DevTypeMap.end()) { + // DevType not mapped + if (Verbose) fprintf(fp, "T: DevType not mapped: %s\n", + D->first.Name.c_str()); + retVal.retT++; + + } else { + if (DevTypes[DTSearch->second].first.Name != D->first.Name){ + // DevType > Index map is broken. + if (Verbose) fprintf(fp, "T: DevTypeMap Broken: %s!=%s\n", + D->first.Name.c_str(), + DevTypes[DTSearch->second].first.Name.c_str()); + retVal.retT++; + } + + if (Idx != DTSearch->second) { + // Index mismatch + if (Verbose) fprintf(fp, "T: DevTypeMap Index mismatch: %s, %u!=%u\n", + D->first.Name.c_str(), Idx, DTSearch->second); + retVal.retT++; + } + } + + //Check the Input Msg Indexes + for(std::vector::const_iterator I + =D->first.InMsgs.begin();I!=D->first.InMsgs.end();I++) + { + const std::vector *InMsgs = &MsgTypes[*I].Inputs; + if (std::find(InMsgs->begin(), InMsgs->end(), Idx) == InMsgs->end()) + { + // MsgType->DevType (Input Message) Vector broken. + if (Verbose) fprintf(fp, "T: MsgType->DevType(InMsg) Vector broken: \ + DevType %u (%s) not found in MsgType InMsg Vector %u\n", + Idx, D->first.Name.c_str(), *I); //DevTypes[Idx].first.Name + retVal.retT++; + } + } + + //Check the Output Msg Indexes + for(std::vector::const_iterator O + =D->first.OuMsgs.begin();O!=D->first.OuMsgs.end();O++) + { + const std::vector *OuMsgs = &MsgTypes[*O].Outputs; + if (std::find(OuMsgs->begin(), OuMsgs->end(), Idx) == OuMsgs->end()) + { + // MsgType->DevType (Output Message) Vector broken. + if (Verbose) fprintf(fp, "T: MsgType->DevType(OuMsg) Vector broken: \ + DevType %u (%s) not found in MsgType OuMsg Vector %u\n", + Idx, D->first.Name.c_str(), *O); + retVal.retT++; + } + } + } +} + +/*============================================================================== + * TaskRecord_t::IntegDevices(): Run an integrity check on the devices in the + * range of DStart-DEnd. + *============================================================================*/ +void TaskRecord_t::IntegDevices(bool Verbose, FILE * fp, unsigned long DStart, + unsigned long DEnd, IntegVals_t &retVal, + AB_ULONG &ExtConCnt) +{ + for(std::vector::const_iterator D = Devices.begin() + DStart; + (D != Devices.end()) && (D < (Devices.begin() + DEnd)); + D++) // Iterate through section of Device vector + { + // Check record type + if((D->RecordType != Device) && (D->RecordType != DeviceExt)) + { + // Non-Device in the Device vector. Something, somewhere has gone very VERY wrong + if (Verbose) fprintf(fp, "Non-Device in Device Vector: %s (%" SYMA_FMT "), %u\n", + D->Name.c_str(), D->Address, D->RecordType); + retVal.ret++; + } else { + // Search Addr Map + AddrMap_t::const_iterator DASearch = AddrMap.find(D->Address); // Find the dev Addr in the map + if (DASearch == AddrMap.end()) { + // DevAddr not mapped - Link broken + if (Verbose) fprintf(fp, "L: DevAddr not mapped: %s, %" SYMA_FMT "\n", + D->Name.c_str(), D->Address); + retVal.retL++; + } else if (DASearch->second != &(*D)) { + // Address does not map to THIS device - Link broken + if (Verbose) fprintf(fp, "L: AddrMap to wrong device: %s, %" PTR_FMT "!=%" PTR_FMT "\n", + D->Name.c_str(), reinterpret_cast(DASearch->second), + reinterpret_cast(&(*D))); + retVal.retL++; + } + + // Search Name Map + NameMap_t::const_iterator DNSearch = NameMap.find(D->Name); // Find the dev Name in the map + if (DNSearch == NameMap.end()) { + // DevName not mapped + if (Verbose) fprintf(fp, "M: Device Name not mapped: %s\n", + D->Name.c_str()); + retVal.retM++; + } else if (DNSearch->second != &(*D)) { + // Name does not map to THIS device - Map Broken + if (Verbose) fprintf(fp, "M: Namemap to wrong device: %s, %" PTR_FMT "!=%" PTR_FMT "\n", + D->Name.c_str(), reinterpret_cast(DNSearch->second), + reinterpret_cast(&(*D))); + retVal.retM++; + } + + // Check Device type Index + if (D->DeviceType >= DevTypes.size()) { + // DeviceType Index out of range + if (Verbose) fprintf(fp, "DeviceType Index out of range: %s (%" SYMA_FMT "), DType: %d>%d\n", + D->Name.c_str(), D->Address, D->DeviceType, + static_cast(DevTypes.size())); + retVal.ret++; + } else { + // Find the pointer to the device record in the Device Type vector + const RecordVect_t *DTypeV = &DevTypes[D->DeviceType].second; + if (std::find(DTypeV->begin(), DTypeV->end(), &(*D)) == DTypeV->end()) + { + // Device not in Device Type vector - Map Broken + if (Verbose) fprintf(fp, "M: Device %s (%" SYMA_FMT ") not in DevicetypeVector %u (%s)\n", + D->Name.c_str(), D->Address, D->DeviceType, + DevTypes[D->DeviceType].first.Name.c_str()); + retVal.retM++; + } + } + + // Search Supervisor + SupMap_t::const_iterator DSSearch = SupMap.find(D->Supervisor); // Find the dev Addr in the map + if (DSSearch == SupMap.end()) { + // Device's Supervisor not found - Link broken + if (Verbose) fprintf(fp, "L: Dev's Supervisor not found in AddrMap: %s, %" SYMA_FMT "\n", + D->Name.c_str(), D->Supervisor); + retVal.retL++; + } else { + // Search Supervsor Vector + const RecordVect_t *SupV = &DSSearch->second; + if (std::find(SupV->begin(), SupV->end(), &(*D)) == SupV->end()) + { + // Pointer to Device Record not found in Supervisor Vector. + if (Verbose) fprintf(fp, "L: Ptr to Device not in Supervisor \ + vector: %s, Supervisor: %" SYMA_FMT "\n", + D->Name.c_str(), D->Supervisor); + retVal.retL++; + } + } + + // Check if the Attribute Index is out of range + if(D->Attribute >= static_cast(AttrTypes.size())) + { + // Attribute Index out of range. + if (Verbose) fprintf(fp, "Attribute Index out of range: %s (%" SYMA_FMT "), Attr: %d>%d\n", + D->Name.c_str(), D->Address, D->Attribute, + static_cast(AttrTypes.size())); + retVal.ret++; + } else if (D->Attribute > -1) { + // Find the pointer to the device record in the Attribute Type vector + const RecordVect_t *ATypeV = &AttrTypes[static_cast(D->Attribute)].second; + if (std::find(ATypeV->begin(), ATypeV->end(), &(*D)) == ATypeV->end()) + { + // Device not in Attribute Type vector - Map Broken + if (Verbose) fprintf(fp, "L: Dev not in Attribute vector: %s\ + , Attribute: %d (%s)\n", D->Name.c_str(), D->Attribute, + AttrTypes[static_cast(D->Attribute)].first.c_str()); + retVal.retM++; + } + } + + // If ExtCon, search ExtCon Vector, ExtConCnt++ + if(D->RecordType == DeviceExt) + { + if (std::find(ExtCon.begin(), ExtCon.end(), &(*D)) == ExtCon.end()) + { + // Device with External Connection not found in ExtCon - Map Broken + if (Verbose) fprintf(fp, "M: Device with External connection not in\ + ExtCon: %s (%" SYMA_FMT ")\n", D->Name.c_str(), D->Address); + retVal.retM++; + } + ExtConCnt++; + } + } + } +} + +/*============================================================================== + * TaskRecord_t::IntegExternals(): Run an integrity check on the externals in + * the range of DStart-DEnd. + *============================================================================*/ +void TaskRecord_t::IntegExternals(bool Verbose, FILE * fp, unsigned long EStart, + unsigned long EEnd, IntegVals_t &retVal) +{ + for(std::vector::const_iterator E = Externals.begin() + EStart; + (E != Externals.end()) && (E < (Externals.begin() + EEnd)); + E++) // Iterate through External vector + { + // Check record type + if(E->RecordType != External) + { + // Non-External in the External vector. Something, somewhere has gone very VERY wrong + if (Verbose) fprintf(fp, "Non-External in External Vector: %s, \ + %" SYMA_FMT ", %d\n", E->Name.c_str(), E->Address, E->RecordType); + retVal.ret++; + } else { + // Search Addr Map + AddrMap_t::const_iterator EASearch = AddrMap.find(E->Address); // Find the dev Addr in the map + if (EASearch == AddrMap.end()) { + // ExtAddr not mapped - Link broken + if (Verbose) fprintf(fp, "L: ExtAddr not mapped: %s, %" SYMA_FMT "\n", + E->Name.c_str(), E->Address); + retVal.retL++; + } else if (EASearch->second != &(*E)) { + // Address does not map to THIS external - Link broken + if (Verbose) fprintf(fp, "L: AddrMap to wrong External: %s, %" PTR_FMT "!=%" PTR_FMT "\n", + E->Name.c_str(), reinterpret_cast(EASearch->second), + reinterpret_cast(&(*E))); + retVal.retL++; + } + + // Search Name Map + NameMap_t::const_iterator ENSearch = NameMap.find(E->Name); // Find the dev Name in the map + if (ENSearch == NameMap.end()) { + // ExtName not mapped + if (Verbose) fprintf(fp, "M: External Name not mapped: %s (%" SYMA_FMT ")\n", + E->Name.c_str(), E->Address); + retVal.retM++; + } else if (ENSearch->second != &(*E)) { + // Name does not map to THIS external - Map Broken + if (Verbose) fprintf(fp, "M: Namemap to wrong external: %s, %" PTR_FMT "!=%" PTR_FMT "\n", + E->Name.c_str(), reinterpret_cast(ENSearch->second), + reinterpret_cast(&(*E))); + retVal.retM++; + } + + // Check Device type Index + if (E->DeviceType >= DevTypes.size()) { + // DeviceType Index out of range + if (Verbose) fprintf(fp, "DeviceType Index out of range: %s (%" SYMA_FMT ")\ + , DType: %u>%d\n", E->Name.c_str(), E->Address, E->DeviceType, + static_cast(DevTypes.size())); + retVal.ret++; + } else { + // Find the pointer to the device record in the Device Type vector + const RecordVect_t *DTypeV = &DevTypes[E->DeviceType].second; + if (std::find(DTypeV->begin(), DTypeV->end(), &(*E)) == DTypeV->end()) + { + // External not in Device Type vector - Map Broken + if (Verbose) fprintf(fp, "M: External %s (%" SYMA_FMT ") not in \ + DeviceType Vector %u (%s)\n", + E->Name.c_str(), E->Address, E->DeviceType, + DevTypes[E->DeviceType].first.Name.c_str()); + retVal.retM++; + } + } + + // Check if the Attribute Index is out of range + if(E->Attribute >= static_cast(AttrTypes.size())) + { + // Attribute Index out of range. + if (Verbose) fprintf(fp, "Attribute Index out of range: %s (%" SYMA_FMT "), \ + Attr: %d>%d\n", E->Name.c_str(), E->Address, E->Attribute, + static_cast(AttrTypes.size())); + retVal.ret++; + } else if (E->Attribute > -1) { + // Find the pointer to the external record in the Attribute Type vector + const RecordVect_t *ATypeV = &AttrTypes[static_cast(E->Attribute)].second; + if (std::find(ATypeV->begin(), ATypeV->end(), &(*E)) == ATypeV->end()) + { + // External not in Attribute Type vector - Map Broken + if (Verbose) fprintf(fp, "L: Ext not in Attribute vector: %s, \ + Attribute: %d (%s)\n", E->Name.c_str(), E->Attribute, + AttrTypes[static_cast(E->Attribute)].first.c_str()); + retVal.retM++; + } + } + } + } +} + +/*============================================================================== + * TaskRecord_t::IntegSupervisors(): Run an integrity check on the supervisors + * in the range of DStart-DEnd. + *============================================================================*/ +void TaskRecord_t::IntegSupervisors(bool Verbose, FILE * fp, unsigned long SStart, + unsigned long SEnd, IntegVals_t &retVal, + AB_UNSIGNED &MappedSupervisors) +{ + for(std::vector::const_iterator S = Supervisors.begin() + SStart; + (S != Supervisors.end()) && (S < (Supervisors.begin() + SEnd)); + S++) // Iterate through Supervisor vector + { + // Check record type + if(S->RecordType != Supervisor) + { + // Non-Supervisor in the Supervisor vector. Something, somewhere has gone very VERY wrong + if (Verbose) fprintf(fp, "Non-Supervisor in Supervisor Vector: %s, \ + %" SYMA_FMT ", %d\n", S->Name.c_str(), S->Address, S->RecordType); + retVal.ret++; + } else { + // Check that Supervisor is listed in Addr Map + AddrMap_t::const_iterator SASearch = AddrMap.find(S->Address); // Find the Addr in the map + if (SASearch == AddrMap.end()) { + // SupAddr not mapped - Link broken + if (Verbose) fprintf(fp, "L: SupAddr not mapped: %s, %" SYMA_FMT "\n", + S->Name.c_str(), S->Address); + retVal.retL++; + } else if (SASearch->second != &(*S)) { + // Address does not map to THIS supervisor - Link broken + if (Verbose) fprintf(fp, "L: AddrMap to wrong Supervisor: %s, %" PTR_FMT "!=%" PTR_FMT "\n", + S->Name.c_str(), reinterpret_cast(SASearch->second), + reinterpret_cast(&(*S))); + retVal.retL++; + } + + // Check that Supervisor is listed in SupMap + SupMap_t::const_iterator SMSearch = SupMap.find(S->Address); + if (SMSearch == SupMap.end()) + { + // SupAddr not mapped - Link broken + if (Verbose) fprintf(fp, "L: SupAddr not in SupMap: %s, %" SYMA_FMT "\n", + S->Name.c_str(), S->Address); + retVal.retL++; + } else { + MappedSupervisors++; + + // Check all devices allocated to supervisor use THIS supervisor + for(RecordVect_t::const_iterator SMV + =SMSearch->second.begin();SMV!=SMSearch->second.end();SMV++) // Iterate through Supervisor's devices + { + if((*SMV)->Supervisor != SMSearch->first) + { + // Supervisor Address in device record does not match THIS supervisor - Link broken + if (Verbose) fprintf(fp, "L: Dev SupAddr mismatch: %s, %"\ + SYMA_FMT "!=%" SYMA_FMT "\n", (*SMV)->Name.c_str(), + (*SMV)->Supervisor, SMSearch->first); + retVal.retL++; + } + } + } + + // Check Device type Index + if (S->DeviceType >= DevTypes.size()) { + // DeviceType Index out of range + if (Verbose) fprintf(fp, "DeviceType Index out of range: Supervisor (%" SYMA_FMT \ + "), DType: %u>%d\n", S->Address, S->DeviceType, + static_cast(DevTypes.size())); + retVal.ret++; + } else { + // Find the pointer to the device record in the Device Type vector + const RecordVect_t *DTypeV = &DevTypes[S->DeviceType].second; + if (std::find(DTypeV->begin(), DTypeV->end(), &(*S)) == DTypeV->end()) + { + // Supervisor not in Device Type vector - Map Broken + if (Verbose) fprintf(fp, "M: Supervisor (%" SYMA_FMT \ + ") not in DeviceType Vector %u (%s)\n", + S->Address, S->DeviceType, + DevTypes[S->DeviceType].first.Name.c_str()); + retVal.retM++; + } + } + } + } +} + +} /* namespace AddressBook */ diff --git a/Source/NameServer/AddressBook/AddressBook_Task.hpp b/Source/NameServer/AddressBook/AddressBook_Task.hpp new file mode 100644 index 00000000..e479cb8e --- /dev/null +++ b/Source/NameServer/AddressBook/AddressBook_Task.hpp @@ -0,0 +1,142 @@ +#ifndef AddressBook_Task_H +#define AddressBook_Task_H + +#include "AddressBook_Defs.hpp" +#include "AddressBook_Record.hpp" + +#include +#include +#include + +#if (__cplusplus >= 201103) && (\ + (defined (__STDC_VERSION__) && (__STDC_VERSION__ >= 201112L)) ||\ + defined (__unix__) || (defined (__APPLE__) && defined (__MACH__))) + //C++11+ and C11+ or POSIX: + // fprintf is thread safe so let's thread stuff! + #include + #include + #define AB_THREADING + + // We need Atomic types if we are using threading. + #define AB_UNSIGNED std::atomic + #define AB_ULONG std::atomic +#else + #define AB_UNSIGNED unsigned + #define AB_ULONG unsigned long + +#endif + + +#define RECOVERABLEINTEGRITY + +namespace AddressBook +{ + +typedef std::map IdxMap_t; +typedef std::vector RecordVect_t; +typedef std::map SupMap_t; +typedef std::map RecordMap_t; +typedef std::map AddrMap_t; +typedef std::map NameMap_t; + +typedef std::pair DevTypePair; +typedef std::pair AttrTypePair; + +struct IntegVals_t { + AB_UNSIGNED ret; + AB_UNSIGNED retT; + AB_UNSIGNED retL; + AB_UNSIGNED retM; +}; + +struct TaskData_t { + TaskData_t(); + TaskData_t(std::string &N, std::string &P, std::string &X, std::string &E, + TaskState_t S, unsigned long DC, unsigned long EC); + + int size() const; // Get the size (in bytes) of the TaskData + + std::string Name; // = ""; + std::string Path; // = ""; + std::string XML; // = ""; + std::string ExecutablePath; // = ""; + TaskState_t State; // = Loaded; + unsigned long DeviceCount; // = 0; // The maximum number of devices in task + unsigned long DeviceCountLd; // = 0; // The number of devices currently loaded + unsigned long ExternalCount; // = 0; // The maximum number of externals in task + unsigned long ExternalCountLd; // = 0; // The number of externals currently loaded + unsigned long SupervisorCount; // = 0; // The number of allocated supervisors + std::vector DeviceTypes; + std::vector MessageTypes; + std::vector AttributeTypes; +}; + + +class TaskRecord_t { +public: + TaskRecord_t(); + TaskRecord_t(std::string &N, std::string &P, std::string &X, std::string &E, + TaskState_t S, unsigned long DC, unsigned long EC); + TaskRecord_t(TaskData_t &Data); + + unsigned Integrity(bool Verbose = false, FILE * = stdout); + + int size() const; // Get the size (in bytes) of the TaskData + + + std::string Name; // = ""; + std::string Path; // = ""; + std::string XML; // = ""; + std::string ExecPath; // = ""; + unsigned long DevCntMax; // = 0; // The expected number of devices + unsigned long ExtCntMax; // = 0; // The expected number of external devices + unsigned long DevCnt; // = 0; // The loaded number of Devices + unsigned long SupCnt; // = 0; // The loaded number of Supervisors + unsigned long ExtCnt; // = 0; // The loaded number of External Devices + + TaskState_t State; // = Loaded; //State of the task + + std::vector Devices; // List of Devices in the task + std::vector Externals; // List of Externals in the task + std::vector Supervisors; // List of Supervisors in the task + + std::vector MsgTypes; // List of task Msg types from XML + //std::vector MsgTypes; // List of task Msg types from XML + std::vector DevTypes; // List of task Dev Types from XML + std::vector AttrTypes; // List of task Attrs from XML + + RecordVect_t ExtCon; // List of Devices with external conns + + // Task String Data Maps + IdxMap_t MsgTypeMap; // Map Msg type string to Idx + IdxMap_t DevTypeMap; // Map Dev type Name to Idx + IdxMap_t AttrTypeMap; // Map Attr type string to Idx + + //Device Maps + SupMap_t SupMap; // Supervisor>DeviceAddress map + AddrMap_t AddrMap; // Addr>record map basis of DNAME, DGRP, SNAME + NameMap_t NameMap; // Name>record map basis of DNAME, DGRP, SNAME + + bool TaskValid; // = true; // Indicate whether the task string info is valid + bool MapValid; // = true; // Indicate whether the task maps are valid + bool LinkValid; // = true; // Indicate whether the Device > Address links are valid + +private: + void IntegDevices(bool Verbose, FILE * fp, unsigned long DStart, + unsigned long DEnd, IntegVals_t &retVal, + AB_ULONG &ExtConCnt); + + void IntegExternals(bool Verbose, FILE * fp, unsigned long EStart, + unsigned long EEnd, IntegVals_t &retVal); + + void IntegSupervisors(bool Verbose, FILE * fp, unsigned long SStart, + unsigned long SEnd, IntegVals_t &retVal, + AB_UNSIGNED &MappedSupervisors); + + void IntegDevTypeMap(bool Verbose, FILE * fp, unsigned long DTStart, + unsigned long DTEnd, IntegVals_t &retVal); +}; + + +} /* namespace AddressBook */ +#endif /* AddressBook_Task_H */ diff --git a/Tests/TestAddressBook.cpp b/Tests/TestAddressBook.cpp new file mode 100644 index 00000000..4890f462 --- /dev/null +++ b/Tests/TestAddressBook.cpp @@ -0,0 +1,745 @@ +/* Tests the AddressBook for functionality and integrity. */ + +#define CATCH_CONFIG_MAIN + +#include "catch.hpp" + +#include "OSFixes.hpp" +#include "AddressBook.hpp" +#include "AddressBook_Defs.hpp" +#include "AddressBook_Task.hpp" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + + +TEST_CASE("AddressBook Small Tests", "[Simple]") +{ + // Create the AddressBook instance + AddressBook::AddressBook AddrBook + = AddressBook::AddressBook(std::string("AddressBookMain")); + AddressBook::TaskData_t taskData; + + //Create a Supervisor devicetype record and add some messagetypes + AddressBook::DevTypeRecord_t SuperDTR("Super"); + SuperDTR.InMsgs.push_back(1); + SuperDTR.OuMsgs.push_back(2); + + //Create a Cell devicetype record and add some messagetytpes + AddressBook::DevTypeRecord_t CellDTR("Cell"); + CellDTR.InMsgs.push_back(0); + CellDTR.InMsgs.push_back(2); + CellDTR.OuMsgs.push_back(0); + CellDTR.OuMsgs.push_back(1); + + //Create a Fixed node devicetype record and add some messagetytpes + AddressBook::DevTypeRecord_t FixedDTR("Fixed"); + FixedDTR.InMsgs.push_back(2); + FixedDTR.OuMsgs.push_back(0); + FixedDTR.OuMsgs.push_back(1); + + + + //========================================================================== + // Add a task (and check that it added correctly) + //========================================================================== + std::string t1Name = "Task1"; + AddressBook::TaskData_t T1Data; + + T1Data.DeviceCount = 5; + T1Data.ExternalCount = 2; + T1Data.Path = "/local/extra/Orchestrator/application_staging/xml"; + T1Data.XML = "task1.xml"; + T1Data.ExecutablePath = "~/"; + T1Data.MessageTypes.push_back("Update"); + T1Data.MessageTypes.push_back("Fin"); + T1Data.MessageTypes.push_back("Done"); + + T1Data.DeviceTypes.push_back(SuperDTR); + T1Data.DeviceTypes.push_back(CellDTR); + T1Data.DeviceTypes.push_back(FixedDTR); + T1Data.AttributeTypes.push_back("Test"); + + // Add the task to the AddressBook + int t1Ret = AddrBook.AddTask(t1Name, T1Data); + REQUIRE(t1Ret == AddressBook::SUCCESS); + + SECTION("Check that a task added correctly", "[Simple]") + { + REQUIRE(AddrBook.GetTaskCount() == 1); // We should have one task, + REQUIRE(AddrBook.IntegCheck() == 0); // that passes integrity. + + // Get the task for running tests on + t1Ret = AddrBook.GetTask(t1Name, taskData); + REQUIRE(t1Ret == AddressBook::SUCCESS); + + REQUIRE(taskData.Name == t1Name); // Check the task name. + REQUIRE(taskData.Path == T1Data.Path); // Check the path string. + REQUIRE(taskData.XML == T1Data.XML); // Check the XML string. + REQUIRE(taskData.ExecutablePath == T1Data.ExecutablePath); // Check the executable path string. + + REQUIRE(taskData.State == AddressBook::Loaded); // Check the task state. + + REQUIRE(taskData.DeviceTypes.size() == T1Data.DeviceTypes.size()); + REQUIRE(taskData.DeviceTypes.size() == 3); // with 5 device types, + REQUIRE(taskData.MessageTypes.size() == 3); // with 3 message types, + REQUIRE(taskData.AttributeTypes.size() == 1); // and 1 attribute type. + + REQUIRE(taskData.DeviceCount == T1Data.DeviceCount); // Expecting 10000 devices + REQUIRE(taskData.DeviceCountLd == 0); // With none loaded. + + REQUIRE(taskData.ExternalCount == T1Data.ExternalCount); // Expecting 1 external device + REQUIRE(taskData.ExternalCountLd == 0); // With none loaded. + + REQUIRE(taskData.SupervisorCount == 0); // Should have no supervisors. + } + //========================================================================== + + + + //========================================================================== + // Add another task + //========================================================================== + std::string t2Name = "Task2"; + AddressBook::TaskData_t T2Data; + + T2Data.DeviceCount = 5; + T2Data.ExternalCount = 2; + T2Data.Path = "/local/extra/Orchestrator/application_staging/xml"; + T2Data.XML = "task2.xml"; + T2Data.ExecutablePath = "~/"; + T2Data.MessageTypes.push_back("Update"); + T2Data.MessageTypes.push_back("Fin"); + T2Data.MessageTypes.push_back("Done"); + + T2Data.DeviceTypes.push_back(SuperDTR); + T2Data.DeviceTypes.push_back(CellDTR); + T2Data.DeviceTypes.push_back(FixedDTR); + + // Add the task to the AddressBook + int t2Ret = AddrBook.AddTask(t2Name, T2Data); + REQUIRE(t2Ret == AddressBook::SUCCESS); + + + SECTION("Check that a second task added correctly", "[Simple]") + { + REQUIRE(AddrBook.GetTaskCount() == 2); // We should have two tasks, + REQUIRE(AddrBook.IntegCheck() == 0); // that pass integrity. + + // Get the task for running tests on + t2Ret = AddrBook.GetTask(t2Name, taskData); + REQUIRE(t2Ret == AddressBook::SUCCESS); + + REQUIRE(taskData.Name == t2Name); // Check the task name. + REQUIRE(taskData.Path == T2Data.Path); // Check the path string. + REQUIRE(taskData.XML == T2Data.XML); // Check the XML string. + REQUIRE(taskData.ExecutablePath == T2Data.ExecutablePath); // Check the executable path string. + + REQUIRE(taskData.State == AddressBook::Loaded); // Check the task state. + + REQUIRE(taskData.DeviceTypes.size() == T2Data.DeviceTypes.size()); + REQUIRE(taskData.DeviceTypes.size() == 3); // with 5 device types, + REQUIRE(taskData.MessageTypes.size() == 3); // with 3 message types, + REQUIRE(taskData.AttributeTypes.size() == 0); // and no attribute types. + + REQUIRE(taskData.DeviceCount == T2Data.DeviceCount); // Expecting 10000 devices + REQUIRE(taskData.DeviceCountLd == 0); // With none loaded. + + REQUIRE(taskData.ExternalCount == T2Data.ExternalCount); // Expecting 1 external device + REQUIRE(taskData.ExternalCountLd == 0); // With none loaded. + + REQUIRE(taskData.SupervisorCount == 0); // Should have no supervisors. + } + //========================================================================== + + + + //========================================================================== + // Check that we can't add a duplicate task + //========================================================================== + SECTION("Check that a duplicate task is correctly rejected", "[Simple]") + { + int t3Ret = AddrBook.AddTask(t2Name, T2Data); + REQUIRE(t3Ret == AddressBook::ERR_TASKNAME_USED); + REQUIRE(AddrBook.GetTaskCount() == 2); // We should have two tasks, + REQUIRE(AddrBook.IntegCheck() == 0); // that pass integrity. + } + //========================================================================== + + + + //========================================================================== + // Delete a task + //========================================================================== + SECTION("Check that tasks can be deleted", "[Simple]") + { + int delRet = AddrBook.DelTask(t2Name); + REQUIRE(delRet == AddressBook::SUCCESS); + REQUIRE(AddrBook.GetTaskCount() == 1); // We should have one task, + REQUIRE(AddrBook.IntegCheck() == 0); // that passes integrity. + } + //========================================================================== + + + + SECTION("Check device handling", "[Simple]") + { + // Get the task + AddrBook.GetTask(t1Name, taskData); + + // Add a supervisor + AddressBook::Record_t SData1; + SData1.Name = ""; + SData1.Address = 0xFFFF0001; + SData1.Rank = 5; + SData1.DeviceType = 0; + SData1.RecordType = static_cast(AddressBook::Supervisor); + try { + unsigned SAdd = AddrBook.AddDevice(t1Name, SData1); + if (SAdd > 0) std::cerr << std::endl << "ERROR adding SData1: " << SAdd << std::endl; + REQUIRE(SAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding SData1: " << msg << std::endl; + std::cin.get(); + } + REQUIRE(AddrBook.GetSupervisorCount(t1Name) == 1); + + + // Add another Supervisor + AddressBook::Record_t SData2; + SData2.Name = ""; + SData2.Address = 0xFFFF0002; + SData2.Rank = 5; + SData2.DeviceType = 0; + SData2.RecordType = static_cast(AddressBook::Supervisor); + try { + unsigned SAdd = AddrBook.AddDevice(t1Name, SData2); + if (SAdd > 0) std::cerr << std::endl << "ERROR adding SData2: " << SAdd << std::endl; + REQUIRE(SAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding SData2: " << msg << std::endl; + std::cin.get(); + } + REQUIRE(AddrBook.GetSupervisorCount(t1Name) == 2); + + + // Add an External + AddressBook::Record_t EData1; + EData1.Name = "E_0,0"; + EData1.Address = 0xFFFFF001; + EData1.DeviceType = 2; + EData1.RecordType = static_cast(AddressBook::External); + try { + unsigned EAdd = AddrBook.AddDevice(t1Name, EData1); + if (EAdd > 0) std::cerr << std::endl << "ERROR adding EData2: " << EAdd << std::endl; + REQUIRE(EAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding EData1: " << msg << std::endl; + std::cin.get(); + } + REQUIRE(AddrBook.GetLoadedExternalCount(t1Name) == 1); + + + // Setup common device data + AddressBook::Record_t DData1; + DData1.Supervisor = 0xFFFF0001; + DData1.DeviceType = 1; + DData1.RecordType = static_cast(AddressBook::Device); + AddressBook::SymAddr_t BaseAddr = 0x00000000; + + + // Add a Device + DData1.Name = "C_0,0"; + DData1.Address = BaseAddr++; + try { + unsigned DAdd = AddrBook.AddDevice(t1Name, DData1); + if (DAdd > 0) std::cerr << std::endl << "ERROR adding Device" + << DData1.Name << " ("<< DData1.Address << "): " + << DAdd << std::endl; + REQUIRE(DAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding Device " + << DData1.Name << " (" << DData1.Address << "): " + << msg << std::endl; + std::cin.get(); + } + REQUIRE(AddrBook.GetLoadedDeviceCount(t1Name) == 1); + + + // Add another Device + DData1.Name = "C_0,1"; + DData1.Address = BaseAddr++; + try { + unsigned DAdd = AddrBook.AddDevice(t1Name, DData1); + if (DAdd > 0) std::cerr << std::endl << "ERROR adding Device" + << DData1.Name << " ("<< DData1.Address << "): " + << DAdd << std::endl; + REQUIRE(DAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding Device " + << DData1.Name << " (" << DData1.Address << "): " + << msg << std::endl; + std::cin.get(); + } + REQUIRE(AddrBook.GetLoadedDeviceCount(t1Name) == 2); + + + // Add another Device + DData1.Name = "C_0,2"; + DData1.Address = BaseAddr++; + try { + unsigned DAdd = AddrBook.AddDevice(t1Name, DData1); + if (DAdd > 0) std::cerr << std::endl << "ERROR adding Device" + << DData1.Name << " ("<< DData1.Address << "): " + << DAdd << std::endl; + REQUIRE(DAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding Device " + << DData1.Name << " (" << DData1.Address << "): " + << msg << std::endl; + std::cin.get(); + } + REQUIRE(AddrBook.GetLoadedDeviceCount(t1Name) == 3); + + + // Add another Device + DData1.Name = "C_0,3"; + DData1.Address = BaseAddr++; + try { + unsigned DAdd = AddrBook.AddDevice(t1Name, DData1); + if (DAdd > 0) std::cerr << std::endl << "ERROR adding Device" + << DData1.Name << " ("<< DData1.Address << "): " + << DAdd << std::endl; + REQUIRE(DAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding Device " + << DData1.Name << " (" << DData1.Address << "): " + << msg << std::endl; + std::cin.get(); + } + REQUIRE(AddrBook.GetLoadedDeviceCount(t1Name) == 4); + + + // Check duplicate device handling + int DDupeRet = AddrBook.AddDevice(t1Name, DData1); + REQUIRE(AddrBook.GetLoadedDeviceCount(t1Name) == 4); // We should have 4 devices + REQUIRE(AddrBook.IntegTask(t1Name, false) == 0); // and pass integrity. + + + // Check that invalid Device types are picked up on + DData1.DeviceType = 5; + DData1.Name = "C_0,4"; + DData1.Address = BaseAddr++; + try { + unsigned DAdd = AddrBook.AddDevice(t1Name, DData1); + REQUIRE(DAdd == AddressBook::ERR_INVALID_DEVTYPE); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding Device " + << DData1.Name << " (" << DData1.Address << "): " + << msg << std::endl; + std::cin.get(); + } + REQUIRE(AddrBook.GetLoadedDeviceCount(t1Name) == 4); + + + // Check that the task is valid + REQUIRE(AddrBook.TaskValid(t1Name) == true); + REQUIRE(AddrBook.TaskMapValid(t1Name) == true); + REQUIRE(AddrBook.TaskLinkValid(t1Name) == true); + + // Check that the rest of the data structure is valid + REQUIRE(AddrBook.GetTaskCount() == 2); // We should have two tasks, + REQUIRE(AddrBook.IntegCheck() == 0); // that passes integrity. + + + + // Add a device that forces another Supervisor + REQUIRE(AddrBook.GetMappedSupervisorCount(t1Name) == 2); + DData1.Supervisor = 0xFFFF0005; + DData1.Name = "C_0,4"; + DData1.DeviceType = 1; + try { + unsigned DAdd = AddrBook.AddDevice(t1Name, DData1); + if (DAdd > 0) std::cerr << std::endl << "ERROR adding Device" + << DData1.Name << " ("<< DData1.Address << "): " + << DAdd << std::endl; + REQUIRE(DAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding Device " + << DData1.Name << " (" << DData1.Address << "): " + << msg << std::endl; + std::cin.get(); + } + REQUIRE(AddrBook.GetLoadedDeviceCount(t1Name) == 5); + REQUIRE(AddrBook.GetSupervisorCount(t1Name) == 2); // Only two added Supervisors + REQUIRE(AddrBook.GetMappedSupervisorCount(t1Name) == 3); // But 3 in the map. + REQUIRE(AddrBook.IntegCheck() != 0); // this fails integrity. + REQUIRE(AddrBook.TaskLinkValid(t1Name) == false); // and the link is invalid + + // Add the missing Supervisor + AddressBook::Record_t SData3; + SData3.Name = ""; + SData3.Address = 0xFFFF0005; + SData3.Rank = 5; + SData3.DeviceType = 0; + SData3.RecordType = static_cast(AddressBook::Supervisor); + try { + unsigned SAdd = AddrBook.AddDevice(t1Name, SData3); + if (SAdd > 0) std::cerr << std::endl << "ERROR adding SData3: " << SAdd << std::endl; + REQUIRE(SAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding SData3: " << msg << std::endl; + std::cin.get(); + } + REQUIRE(AddrBook.GetLoadedDeviceCount(t1Name) == 5); + REQUIRE(AddrBook.GetSupervisorCount(t1Name) == 3); + REQUIRE(AddrBook.GetMappedSupervisorCount(t1Name) == 3); + REQUIRE(AddrBook.IntegCheck() == 0); // Should now pass integrity. +#ifdef RECOVERABLEINTEGRITY + // If RECOVERABLEINTEGRITY is defined, the link should be valid. + REQUIRE(AddrBook.TaskLinkValid(t1Name) == true); +#else + // Otherwise it is invalid and we need to relink. + REQUIRE(AddrBook.TaskLinkValid(t1Name) == false); + REQUIRE(AddrBook.BuildLink(t1Name) == AddressBook::SUCCESS); + REQUIRE(AddrBook.TaskLinkValid(t1Name) == true); // Link should now be valid +#endif + // Check that the rest of the task is valid + REQUIRE(AddrBook.TaskValid(t1Name) == true); + REQUIRE(AddrBook.TaskMapValid(t1Name) == true); + + + } + + + //TODO: Add more checks to: + // Check that adding too many devices is handled + // Check that adding too many externals is handled + // Check that adding too many Supervisors is handled + + // Update a device + + // Find by Supervisor + // Find by Attribute + // Find by Messages + // Clear Task + // Task States + + // Intentionally mess with message links + + // Rebuild Map + // Rebuild Task + // Integrity check after futzing + +} + + +TEST_CASE("AddressBook Large Plate Test", "[Simple]") +{ + // Create the AddressBook instance + AddressBook::AddressBook AddrBook + = AddressBook::AddressBook(std::string("AddressBookMain")); + + std::string tName = "plate_1000x1000"; + AddressBook::TaskData_t taskData; + + + //========================================================================== + // Create a "fake" 1000x1000 heated plate. + //========================================================================== + AddressBook::TaskData_t TData; + + TData.DeviceCount = 65536; + TData.ExternalCount = 1; + TData.Path = "/local/extra/Orchestrator/application_staging/xml"; + TData.XML = "plate_1000x1000.xml"; + TData.ExecutablePath = "~/"; + TData.MessageTypes.push_back("Update"); + TData.MessageTypes.push_back("Fin"); + TData.MessageTypes.push_back("Done"); + + //Create a Supervisor devicetype record and add some messagetypes + AddressBook::DevTypeRecord_t SuperDTR("Super"); + SuperDTR.InMsgs.push_back(1); + SuperDTR.OuMsgs.push_back(2); + + //Create a Cell devicetype record and add some messagetytpes + AddressBook::DevTypeRecord_t CellDTR("Cell"); + CellDTR.InMsgs.push_back(0); + CellDTR.InMsgs.push_back(2); + CellDTR.OuMsgs.push_back(0); + CellDTR.OuMsgs.push_back(1); + + //Create a Fixed node devicetype record and add some messagetytpes + AddressBook::DevTypeRecord_t FixedDTR("Fixed"); + FixedDTR.InMsgs.push_back(2); + FixedDTR.OuMsgs.push_back(0); + FixedDTR.OuMsgs.push_back(1); + + //Create a Router devicetype record and add some messagetytpes + AddressBook::DevTypeRecord_t RouterDTR("Router"); + RouterDTR.InMsgs.push_back(1); + RouterDTR.OuMsgs.push_back(1); + RouterDTR.OuMsgs.push_back(2); + + //Create a Extern devicetype record and add some messagetytpes + AddressBook::DevTypeRecord_t ExternDTR("Extern"); + ExternDTR.InMsgs.push_back(2); + ExternDTR.OuMsgs.push_back(0); + + // Add all of the device types to the Task Data + TData.DeviceTypes.push_back(SuperDTR); + TData.DeviceTypes.push_back(CellDTR); + TData.DeviceTypes.push_back(FixedDTR); + TData.DeviceTypes.push_back(RouterDTR); + TData.DeviceTypes.push_back(ExternDTR); + + // Add an attribute + TData.AttributeTypes.push_back("Test"); + + // Add the task to the AddressBook + AddrBook.AddTask(tName, TData); + //========================================================================== + + + // Get the task for running tests on + AddrBook.GetTask(tName, taskData); + + + + + + //========================================================================== + //Check that the task was added and read correctly + //========================================================================== + SECTION("Check that we have the right number of devices in the task data", "[Simple]") + { + REQUIRE(AddrBook.GetTaskCount() == 1); // We should have one task, + + REQUIRE(taskData.Name == tName); // Check the task name. + REQUIRE(taskData.Path == TData.Path); // Check the path string. + REQUIRE(taskData.XML == TData.XML); // Check the XML string. + REQUIRE(taskData.ExecutablePath == TData.ExecutablePath); // Check the executable path string. + + REQUIRE(taskData.State == AddressBook::Loaded); // Check the task state. + + REQUIRE(taskData.DeviceTypes.size() == TData.DeviceTypes.size()); + REQUIRE(taskData.DeviceTypes.size() == 5); // with 5 device types, + REQUIRE(taskData.MessageTypes.size() == 3); // with 3 message types, + REQUIRE(taskData.AttributeTypes.size() == 1); // and 1 attribute type. + + REQUIRE(taskData.DeviceCount == TData.DeviceCount); // Expecting 10000 devices + REQUIRE(taskData.DeviceCountLd == 0); // With none loaded. + + REQUIRE(taskData.ExternalCount == 1); // Expecting 1 external device + REQUIRE(taskData.ExternalCountLd == 0); // With none loaded. + + REQUIRE(taskData.SupervisorCount == 0); // Should have no supervisors. + } + //========================================================================== + + + + //========================================================================== + // Add a supervisor + //========================================================================== + AddressBook::Record_t SData1; + SData1.Name = ""; + SData1.Address = 0xFFFF0001; + SData1.Rank = 5; + SData1.DeviceType = 0; // SuperDTR + SData1.RecordType = static_cast(AddressBook::Supervisor); + + REQUIRE(taskData.DeviceTypes.size() == 5); // with 5 device types, + + try { + unsigned SAdd = AddrBook.AddDevice(tName, SData1); + if (SAdd > 0) std::cerr << std::endl << "ERROR adding SData1: " << SAdd << std::endl; + REQUIRE(SAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding SData1: " << msg << std::endl; + std::cin.get(); + } + //========================================================================== + + + //========================================================================== + // Add two fixed nodes + //========================================================================== + AddressBook::Record_t FData1; + FData1.Name = "C_0,0"; + FData1.Address = 0xFFE00000; + FData1.Supervisor = 0xFFFF0001; + FData1.DeviceType = 2; + FData1.RecordType = static_cast(AddressBook::DeviceExt); + + try { + unsigned FAdd = AddrBook.AddDevice(tName, FData1); + if (FAdd > 0) std::cerr << std::endl << "ERROR adding FData1: " << FAdd << std::endl; + REQUIRE(FAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding FData1: " << msg << std::endl; + std::cin.get(); + } + + + AddressBook::Record_t FData2; + FData2.Name = "C_255,255"; + FData2.Address = 0xFFE00001; + FData2.Supervisor = 0xFFFF0001; + FData2.DeviceType = 2; + FData2.RecordType = static_cast(AddressBook::DeviceExt); + + try { + unsigned FAdd = AddrBook.AddDevice(tName, FData2); + if (FAdd > 0) std::cerr << std::endl << "ERROR adding FData2: " << FAdd << std::endl; + REQUIRE(FAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding FData2: " << msg << std::endl; + std::cin.get(); + } + //========================================================================== + + + //========================================================================== + // Add an External + //========================================================================== + AddressBook::Record_t EData1; + EData1.Name = "E_0,0"; + EData1.Address = 0xFFFFF001; + EData1.DeviceType = 4; + EData1.RecordType = static_cast(AddressBook::External); + + try { + unsigned EAdd = AddrBook.AddDevice(tName, EData1); + if (EAdd > 0) std::cerr << std::endl << "ERROR adding EData2: " << EAdd << std::endl; + REQUIRE(EAdd == 0); + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding EData1: " << msg << std::endl; + std::cin.get(); + } + //========================================================================== + + + //========================================================================== + // Add 999998 Cells + //========================================================================== + AddressBook::SymAddr_t BaseAddr = 0x00000000; + + AddressBook::Record_t DData1; + DData1.Supervisor = 0xFFFF0001; + DData1.DeviceType = 1; + DData1.RecordType = static_cast(AddressBook::Device); + + for (long i = 0; i < 256; i++) + { + //if(i%100 == 0) std::cout << "\t" << i*1000 << "..." << std::endl; + for (long j = 0; j < 256; j++) + { + if (!(i == 0 && j == 0) && !(i == 255 && j == 255)) + { + DData1.Name = "C_" + TO_STRING(i) + "," + TO_STRING(j); + DData1.Address = BaseAddr++; + + try{ + unsigned DAdd = AddrBook.AddDevice(tName, DData1); + if (DAdd > 0) std::cerr << std::endl << "ERROR adding Device" + << DData1.Name << " (" + << DData1.Address << "): " + << DAdd << std::endl; + } catch (const char* msg) { + std::cerr << std::endl << "ERROR adding Device " + << DData1.Name << " (" + << DData1.Address << "): " + << msg << std::endl; + std::cin.get(); + } + } + } + } + //========================================================================== + + + // Get the task for running tests on + AddrBook.GetTask(tName, taskData); + + //========================================================================== + //Check that the task hasn't been altered by adding devices + //========================================================================== + SECTION("Check that we have the right number of devices in the task data after adding", "[Simple]") + { + REQUIRE(AddrBook.GetTaskCount() == 1); // We should have one task, + + REQUIRE(taskData.Name == tName); // Check the task name. + REQUIRE(taskData.Path == TData.Path); // Check the path string. + REQUIRE(taskData.XML == TData.XML); // Check the XML string. + REQUIRE(taskData.ExecutablePath == TData.ExecutablePath); // Check the executable path string. + + REQUIRE(taskData.State == AddressBook::Loaded); // Check the task state. + + //REQUIRE(taskData.DeviceTypes.size() == TData.DeviceTypes.size()); + REQUIRE(taskData.DeviceTypes.size() == 5); // with 5 device types, + REQUIRE(taskData.MessageTypes.size() == 3); // with 3 message types, + REQUIRE(taskData.AttributeTypes.size() == 1); // and 1 attribute type. + + REQUIRE(taskData.DeviceCount == TData.DeviceCount); // Expecting 10000 devices + REQUIRE(taskData.DeviceCountLd == TData.DeviceCount); // With all loaded. + + REQUIRE(taskData.ExternalCount == 1); // Expecting 1 external device + REQUIRE(taskData.ExternalCountLd == 1); // With 1 loaded. + + REQUIRE(taskData.SupervisorCount == 1); // Should have one supervisors. + + + } + //========================================================================== + + + //========================================================================== + // Search for devices + //========================================================================== + SECTION("Check that devices added as expected and can be found by name and address", "[Simple]") + { + std::string DName = "C_75,199"; // Name of a device we are going to search for + AddressBook::SymAddr_t DNameAddr = 0x4BC6; // and its address + + std::string DAddrName = "C_1,119"; // and its name + AddressBook::SymAddr_t DAddr = 0x0176; // Address to search for + + const AddressBook::Record_t * DeviceRecord; // pointer to a const-qualified Device record + + // Find device by name + int a = AddrBook.FindDevice(tName, DName, DeviceRecord); + REQUIRE(a == 0); // Found the device? + if(a == 0) + { + REQUIRE(DName == DeviceRecord->Name); // Check the name + REQUIRE(DNameAddr == DeviceRecord->Address); // Check the address + REQUIRE(taskData.DeviceTypes[DeviceRecord->DeviceType].Name == "Cell"); // Check the type + } + + // Find device by address + int b = AddrBook.FindDevice(tName, DAddr, DeviceRecord); + REQUIRE(b == 0); // Found the device? + if(b == 0) + { + REQUIRE(DAddrName == DeviceRecord->Name); // Check the name + REQUIRE(DAddr == DeviceRecord->Address); // Check the address + REQUIRE(taskData.DeviceTypes[DeviceRecord->DeviceType].Name == "Cell"); // Check the type + } + } + + SECTION("Integrity Check - this will take some time", "[Simple]") + { + int result = AddrBook.IntegTask(tName, false); + REQUIRE(result == 0); + } +}