// // File: hdbRepos.cpp // // Legal Notice: This file is part of the HadronZoo C++ Class Library. Copyright 2025 HadronZoo Project (http://www.hadronzoo.com) // // The HadronZoo C++ Class Library is free software: You can redistribute it, and/or modify it under the terms of the GNU Lesser General Public License, as published by the Free // Software Foundation, either version 3 of the License, or any later version. // // The HadronZoo C++ Class Library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR // A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public License along with the HadronZoo C++ Class Library. If not, see http://www.gnu.org/licenses. //
// // Implimentation of the HadronZoo Proprietary Database Suite //
#include <iostream> #include <fstream> #include <cstdio>
#include <unistd.h> #include <stdlib.h> #include <fcntl.h> #include <string.h> #include <sys/types.h> #include <sys/stat.h>
#include "hzBasedefs.h" #include "hzString.h" #include "hzChars.h" #include "hzChain.h" #include "hzDate.h" #include "hzTextproc.h" #include "hzCodec.h" #include "hzDocument.h" #include "hzDirectory.h" #include "hzDatabase.h" #include "hzDelta.h" #include "hzProcess.h"
using namespace std ;
/* ** Variables */
extern hzDeltaClient* _hzGlobal_DeltaClient ; // Total of current delta clients
/* ** Prototypes */
uint32_t Datatype2Size (hdbBasetype eType) ; const char* _hds_showinitstate (hdbIniStat nState) ; void _hdb_ck_initstate (const hzString& objName, hdbIniStat eActual, hdbIniStat eExpect) ;
/* ** Chain block bucket regime */
/* ** hdbObjRepos::_cache_chain Functions */
void hdbObjRepos::_cache::Clear (void) { // Clear cache // // Arguments: None // Returns: None
m_Chain.Clear() ; }
hdbObjRepos::_c_blk* hdbObjRepos::_cache::_findBlock (uint32_t objId) { // Find the address of the chain block for the given object id. This is done by a binary chop on the chain of blocks. // // Argument: objId The object id // // Returns: Pointer to the block or NULL if the object does not exist
_hzfunc("_hz_xchain::_findBlock") ;
_c_blk* pBloc ; // Current chain block uint32_t nMax ; // Number of blocks -1 uint32_t nDiv ; // Binary chop divider uint32_t nPos ; // Starting position uint32_t found ; // Number found/limit checker
if (!this) Fatal("No Instance\n") ;
if (!objId) return 0 ; if (!m_Chain.Count()) return 0 ;
if (m_Chain.Count() == 1) return m_Chain[0] ;
nMax = m_Chain.Count() - 1 ; for (found = 2 ; found < nMax ; found *= 2) ; nDiv = found / 2 ; nPos = found - 1 ;
for (;;) { if (nPos > nMax) { if (!nDiv) break ; nPos -= nDiv ; nDiv /= 2 ; continue ; }
pBloc = m_Chain[nPos] ;
if (objId > pBloc->m_nHi) { // Go higher if (!nDiv) break ; nPos += nDiv ; nDiv /= 2 ; continue ; }
if (objId < pBloc->m_nLo) { // Go lower if (!nDiv) break ; nPos -= nDiv ; nDiv /= 2 ; continue ; }
found = nPos ; return m_Chain[found] ; }
return 0 ; }
/* ** hdbObjRepos::_cache Functions */
hzEcode hdbObjRepos::_cache::Init (const hdbClass* pClass) { // Initialize the _cache. Create the _hz_xchain instance // // Argument: pClass The data class // // Returns: E_OK // // Exits: E_ARGUMENT If no class is supplied // E_NOINIT If supplied class is not initialized // E_DUPLICATE If Cache is already set to a class
if (!pClass) hzexit(E_ARGUMENT, "No class supplied") ; if (!pClass->IsInit()) hzexit(E_NOINIT, "Class not initialized") ; if (m_pClass) hzexit(E_DUPLICATE, "Cache already has a data class") ;
m_pClass = pClass ; return E_OK ; }
hzEcode hdbObjRepos::_cache::FetchEDO (hzChain& edo, uint32_t objId) { // Fetch the EDO indicated by the supplied object id, into the supplied chain // // Arguments: 1) edo hzChain as EDO recepticle // 2) objId The object id // // Returns: E_NOTFOUND If an EDO of the id is not found // E_OK Operation successful
_hzfunc("hdbObjRepos::_cache::FetchEDO") ;
xbufIter zi ; // Node data iterator xbufIter edoStart ; // Start of EDO marker xbufIter edoMark ; // Tail of EDO marker _c_blk* pBloc ; // Current chain block
uint32_t nLen ; // EDO length uint32_t nId ; // EDO object id
if (!this) Fatal("No Instance\n") ; if (!objId) return hzerr(E_NOTFOUND, "Illegal object ID (0)") ;
edo.Clear() ;
pBloc = _findBlock(objId) ; if (!pBloc) return hzerr(E_NOTFOUND, "No block identified for object %u", objId) ;
// Now iterate EDOs in block. Read the length and ids from serial integers and iterate until either an EDO of the object id is found or surpassed zi = pBloc->m_edo_space ;
for (; !zi.eof() ;) { // Read EDO length and id edoStart = zi ; ReadSerialUINT32(nLen, zi) ; edoMark = zi ; ReadSerialUINT32(nId, zi) ; //threadLog("EDO id %u len %u oset %u\n", nId, nLen, zi._oset()) ;
if (nId < objId) { zi = edoMark ; zi += nLen ; continue ; }
if (nId > objId) return E_NOTFOUND ;
// EDO found, advance marker to the end edoMark += nLen ; break ; }
// Copy the EDO to the chain for (zi = edoStart ; !zi.eof() && zi != edoMark ; zi++) { edo.AddByte(*zi) ; } return E_OK ; }
hzEcode hdbObjRepos::_cache::CommitEDO (const hzChain& edo, uint32_t objId, bool bLoad) { // Commit an EDO to the cache. // // If the supplied object Id is 0, the EDO is a new object so the commit is an INSERT - in which case the object will be placed at the end, and the id issued in respect of it, // will be the highest thusfar issues. If the supplied object id is non-zero, the commit is an UPDATE and it must be of an object that already exists and has not been deleted. // // In an UPDATE, the supplied EDO replaces the existing EDO. The supplied EDO may be shorter, longer, or the same size as the existing EDO. If the same size, the existing EDO // is overwritten, otherwise the cache block is recreated. All data up to the existing EDO is copied to a new block, the supplied EDO is then added to the new block, then all // data after the existing EDO is copied over - then the new block replaces the old. // // Arguments: 1) edo EDO to commit (supplied as hzChain) // 2) objId The object id // // Returns: E_CORRUPPT If the supplied object id is non-zero but no cache block could be identified. // E_NOTFOUND If the supplied object id addresses a deleted object // E_OK Operation successful
_hzfunc("hdbObjRepos::_cache::CommitEDO") ;
hzXbuf newBuf ; // New buffer (result of insert) chIter ei ; // EDO iterator xbufIter zi ; // Iterator xbufIter xi ; // Reserve iterator _c_blk* pBloc ; // Current chain block uint32_t nLen ; // EDO length uint32_t nId ; // EDO object id
// Validate if (!this) hzexit(E_CORRUPT, "No repository instance") ; if (!m_pClass) hzexit(E_NOINIT, "Cache not initialized") ;
/* Diags hzChain err ; err << "EDO is [ " ; for (ei = edo ; !ei.eof() ; ei++) { err.Printf("%02x ", (uchar) *ei) ; } err << "]\n" ; threadLog(err) ; threadLog("Commiting EDO objId %d\n", objId) ; */
if (!objId) hzexit(E_ARGUMENT, "Invalid object ID") ;
// Virgin cache if (!m_Chain.Count()) { pBloc = new _c_blk() ; m_Chain.Add(pBloc) ; }
//if (!objId || objId > m_nTopId) if (objId > m_nTopId) { // EDO is taken to be new so objId is set at current highest + 1. Note this is not the EDO population as some EDOs may have been deleted. The position of the new EDO will // be at the end of the last block in the chain.
pBloc = m_Chain[m_Chain.Count()-1] ; if (pBloc->m_edo_space.Size() > 4000) { pBloc = new _c_blk() ; m_Chain.Add(pBloc) ; pBloc->m_nLo = objId ; threadLog("Allocating new block %p low %u\n", pBloc, pBloc->m_nLo) ; } pBloc->m_edo_space += edo ; pBloc->m_nHi = objId ; m_nEDO++ ; m_nTopId++ ;
return E_OK ; }
// objId supplied so looking for an existing EDO to replace. If not found this is an error pBloc = _findBlock(objId) ; if (!pBloc) return hzerr(E_CORRUPT, "No block located") ;
// Now iterate EDOs in block. Read the length and ids from serial integers and iterate until either an EDO of the object id is found or surpassed //zi.SetPosn(pBloc, pBloc->m_nOsetEDO) ;
if (objId > pBloc->m_nHi) { // New object will be the highest pBloc->m_edo_space += edo ; pBloc->m_nHi = objId ; m_nEDO++ ; } else if (objId < pBloc->m_nLo) { // New object will be the lowest newBuf += edo ; newBuf += pBloc->m_edo_space ; pBloc->m_edo_space = newBuf ; pBloc->m_nLo = objId ; m_nEDO++ ; } else { // New object is in-between so iterate to the correct position zi = pBloc->m_edo_space ;
for (; !zi.eof() ;) { xi = zi ; ReadSerialUINT32(nLen, zi) ; ReadSerialUINT32(nId, zi) ;
if (nId > objId) return E_NOTFOUND ;
if (nId < objId) { xi += nLen ; zi = xi ; continue ; } break ; }
if (nId > objId) { // The object id does not exist in the block. In normal operation this is an error since object ids are non-recurrent. During the initial delta load (bLoad=true), this // is allowed since deltas are not necessarily in order. if (!bLoad) return E_NOTFOUND ;
// xi is the position of the new edo for (zi = pBloc->m_edo_space ; zi != xi ; zi++) { newBuf.AddByte(*zi) ; } newBuf += edo ; for (; !xi.eof() ; xi++) { newBuf.AddByte(*zi) ; } pBloc->m_edo_space = newBuf ; } else { // xi marks the existing object. If the size is the same, just overwrite if (nLen == edo.Size()) { for (ei = edo ; !ei.eof() ; ei++) { xi = *ei ; xi++ ; } } else { // Size not the same. Write everything up to xi to newBuf, write edo to newBuf, write everything north of xi + nLen to newBuf, make newBuf the new edo_space. for (zi = pBloc->m_edo_space ; zi != xi ; zi++) { newBuf.AddByte(*zi) ; } newBuf += edo ; for (xi += nLen ; !xi.eof() ; xi++) { newBuf.AddByte(*zi) ; } pBloc->m_edo_space = newBuf ; } } }
return E_OK ; }
void hdbObjRepos::_cache::Show (hzChain& Z, bool bDetail) const { // Show node content
_hzfunc("hdbObjRepos::_cache::Show") ;
xbufIter zi ; // X-buf iterator _c_blk* pBloc ; // Current chain block uint32_t n ; // Block counter uint32_t byte ; // Byte
for (n = 0 ; n < m_Chain.Count() ; n++) { pBloc = m_Chain[n] ; Z.Printf("Node %u: Lo %u Hi %u Size %u\n", n, pBloc->m_nLo, pBloc->m_nHi, pBloc->m_edo_space.Size()) ;
if (bDetail) { for (zi = pBloc->m_edo_space ; !zi.eof() ; zi++) { byte = *zi & 0xff ; Z.Printf("%02x,", byte) ; } Z.AddByte(CHAR_NL) ; } } }
/* ** hdbObjRepos Functions */
hdbObjRepos::hdbObjRepos (hdbADP& adp) { m_pADP = &adp ;
m_pBR_Delta = 0 ; m_pBR_Datum = 0 ; m_pMain = 0 ; m_nSeqId = m_nPopulation = 0 ; m_DeltaId = 0 ; m_bBinaries = false ; m_eReposInit = HDB_CLASS_INIT_NONE ; }
hdbObjRepos::~hdbObjRepos (void) { if (m_pMain) m_pMain->Clear() ; delete m_pMain ; }
hzEcode hdbObjRepos::InitStart (const hdbClass* pNative, const hzString& name, const hzString& workdir, hdbReposMode eMode) { // Begin repository initialization sequence. This function sets the repository native class, names the repository and the working directory (location of data files). Once this // function has completed, it may be followed by calls to InitMbrIndex() to add member-wise indexes to the repository. Lastly InitDone() is called to complete the process. // // Arguments: 1) pNative The data class // 2) name The repository name // 3) workdir The operaional directory // 4) bCache Use RAM Primacy // // Returns: E_ARGUMENT If no data class is supplied // E_NOINIT If no class members have been defined // E_INITDUP If this is a repeat call // E_DUPLICATE If the cache already exists // E_OK If the operation was successful
_hzfunc("hdbObjRepos::InitStart") ;
//const hdbMember* pMbr ; // Named class member //uint32_t nIndex ; // Member iterator hzEcode rc ; // Return code
if (!this) hzexit(E_CORRUPT, "No hdbObjRepos instance") ;
// Check init state and state of supplied class _hdb_ck_initstate(name, m_eReposInit, HDB_CLASS_INIT_NONE) ;
// Check data class has been supplied and is initialized if (!pNative) return hzerr(E_ARGUMENT, "No data class supplied") ;
if (!pNative->IsInit()) return hzerr(E_NOINIT, "Supplied class (%s) is not initialized", pNative->txtName()) ;
if (pNative->HasBinaries()) { if (eMode == HDB_REPOS_CACHE) { hzwarn(E_TYPE, "Ignoring CACHE mode, using DUAL") ; eMode = HDB_REPOS_DUAL ; } }
// Ensure Repository Name is Unique if (!name) return hzerr(E_ARGUMENT, "No name supplied") ;
if (m_pADP->GetObjRepos(name)) return hzerr(E_DUPLICATE, "Repository %s already exists", *name) ;
// Ensure working directory is given and operational if (!workdir) return hzerr(E_ARGUMENT, "No working directory supplied for object cache %s", *name) ;
rc = AssertDir(*workdir, 0777) ; if (rc != E_OK) return hzerr(rc, "Cannot assert working directory %s for object cache %s\n", *workdir, *name) ;
// Proceed with initialization m_pClass = pNative ; m_Name = name ; m_Workdir = workdir ;
if (eMode == HDB_REPOS_HARD || eMode == HDB_REPOS_DUAL) { // Set up the member data binary datum repostory if (pNative->HasBinaries()) { m_nameBR_Datum = m_Name + "_br_datum" ;
m_pBR_Datum = new hdbBinRepos(*m_pADP) ; rc = m_pBR_Datum->Init(m_nameBR_Datum, m_Workdir) ; if (rc != E_OK) return hzerr(rc, "Failed to initialize binary data store: Repos %s, Datum BR (%s), workdir %s\n", *m_Name, *m_nameBR_Datum, *m_Workdir) ; }
// Set up the default binary datum repostory if (!m_pBR_Delta) { m_nameBR_Delta = m_Name + "_br_delta" ;
m_pBR_Delta = new hdbBinRepos(*m_pADP) ; rc = m_pBR_Delta->Init(m_nameBR_Delta, m_Workdir) ; if (rc != E_OK) return hzerr(rc, "Failed to initialize binary data store %s (%s)\n", *m_nameBR_Delta, *m_Workdir) ; } } // Set up RAM Primacy cache if applicable if (eMode == HDB_REPOS_CACHE || eMode == HDB_REPOS_DUAL) { m_pathCD = m_Workdir ; m_pathCD += "/" ; m_pathCD += m_Name ; m_pathCD += ".cache" ;
m_pMain = new _cache() ; m_pMain->Init(m_pClass) ; }
// Set init state m_eReposInit = HDB_REPOS_INIT_PROG ;
// Insert the repository m_pADP->RegisterObjRepos(this) ; return E_OK ; }
hzEcode hdbObjRepos::InitMbrIndex (const hdbMember* pMbr, bool bUnique) { // Add an index based on the supplied member name. Find the member in the class and from the datatype, this will determine which sort of index // should be set up. // // Arguments: 1) mbrName Name of member index shall apply to // 2) bUnique Flag if value uniqness applies // // Returns: E_NOINIT If the cache initialization sequence has not been started // E_ARGUMENT If the member name is not supplied // E_SEQUENCE If the cache initialization has been completed by InitDone() // E_NOTFOUND If the named member is not found in the cache class // E_TYPE If the named member is of a type that cannot accept an index // E_OK If the index is successfully created
_hzfunc("hdbObjRepos::InitMbrIndex") ;
//const hdbMember* pMbr ; // Named class member hdbIndex* pIdx ; // The index to be added hzString iname ; // Index name of the form repos::member hzEcode rc = E_OK ; // Return code
// Check init state _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_INIT_PROG) ;
if (!m_pClass) return hzerr(E_NOINIT, "No cache class set up") ; if (!pMbr) return hzerr(E_ARGUMENT, "No member supplied") ;
if (pMbr->Class() != m_pClass) return hzerr(E_NOTFOUND, "No such member as %s in class %s\n", pMbr->txtName(), m_pClass->txtType()) ;
if (pMbr->Posn() < 0 || pMbr->Posn() >= m_pClass->MbrCount()) return hzerr(E_NOTFOUND, "Member %s has no defined position within the class\n", pMbr->txtName()) ;
// Member's datatype will determine the type of index pIdx = 0 ; switch (pMbr->Basetype()) { case BASETYPE_EMADDR: case BASETYPE_URL: pIdx = new hdbIndexUkey() ; break ;
case BASETYPE_STRING: case BASETYPE_IPADDR: case BASETYPE_TIME: case BASETYPE_SDATE: case BASETYPE_XDATE: case BASETYPE_DOUBLE: case BASETYPE_INT64: case BASETYPE_INT32: case BASETYPE_UINT64: case BASETYPE_UINT32: case BASETYPE_UINT16: case BASETYPE_UBYTE: pIdx = new hdbIndexUkey() ; break ;
case BASETYPE_INT16: case BASETYPE_BYTE: case BASETYPE_ENUM: pIdx = new hdbIndexEnum() ; break ;
case BASETYPE_TEXT: case BASETYPE_TXTDOC: pIdx = new hdbIndexText() ; break ;
case BASETYPE_CLASS: case BASETYPE_BINARY: hzerr(E_TYPE, "Invalid member type. No Index allowed") ; rc = E_TYPE ; break ;
default: break ; }
m_mapIndex.Insert(pMbr->DeltaId(), pIdx) ; m_eReposInit = HDB_REPOS_INIT_PROG ;
return rc ; }
hzEcode hdbObjRepos::InitMbrIndex (const hzString& mbrName, bool bUnique) { // Add an index based on the supplied member name. Find the member in the class and from the datatype, this will determine which sort of index // should be set up. // // Arguments: 1) mbrName Name of member index shall apply to // 2) bUnique Flag if value uniqness applies // // Returns: E_NOINIT If the cache initialization sequence has not been started // E_ARGUMENT If the member name is not supplied // E_SEQUENCE If the cache initialization has been completed by InitDone() // E_NOTFOUND If the named member is not found in the cache class // E_TYPE If the named member is of a type that cannot accept an index // E_OK If the index is successfully created
_hzfunc("hdbObjRepos::InitMbrIndex") ;
const hdbMember* pMbr ; // Named class member
// Check init state _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_INIT_PROG) ;
if (!m_pClass) return hzerr(E_NOINIT, "No cache class set up") ; if (!mbrName) return hzerr(E_ARGUMENT, "No member name supplied") ;
pMbr = m_pClass->GetMember(mbrName) ; if (!pMbr) return hzerr(E_NOTFOUND, "No such member as %s in class %s\n", *mbrName, m_pClass->txtType()) ;
return InitMbrIndex(pMbr, bUnique) ; }
hzEcode hdbObjRepos::InitMbrRepos (const hzString& mbrName, const hzString& reposName) { // By default subclass data objects are embedded within host class data objects. This function directs the repository to hold subclass data objects in another repository. This // is done on a per-member basis and only applies to member with of a CLASS data type. // // Arguments: 1) mbrName The member name. The named member must exist and be of a CLASS data type. // 2) pRepos Pointer to the target repository // // Returns: E_NOTFOUND If the named member does not exist. // E_TYPE If the named member is not of a BINARY data type // E_OK If the operation was successful.
_hzfunc("hdbObjRepos::InitMbrRepos") ;
const hdbObjRepos* pRepos ; // External repository const hdbMember* pMbr ; // Named class member
_hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_INIT_PROG) ;
pMbr = m_pClass->GetMember(mbrName) ; if (!pMbr) return hzerr(E_NOTFOUND, "No such member as %s in class %s\n", *mbrName, m_pClass->txtType()) ;
if (pMbr->Basetype() != BASETYPE_BINARY && pMbr->Basetype() != BASETYPE_TEXT && pMbr->Basetype() != BASETYPE_TXTDOC) return hzerr(E_TYPE, "Member %s has non binary base type", *mbrName) ;
if (!reposName) return hzerr(E_ARGUMENT, "No Binary Repository named") ;
// A pre-existing hdbObjRepos has been named so the member will use this. pRepos = m_pADP->GetObjRepos(reposName) ; if (!pRepos) return hzerr(E_NOTFOUND, "Repository %s does not exist", *reposName) ; m_mapRepos.Insert(pMbr->Posn(), pRepos) ; return E_OK ; }
hzEcode hdbObjRepos::InitDone (void) { // Complete repository initialization. // // Deal with files if the working directory has been supplied. If files bearing the repository name exists in the stated working directory, these are assumed to be data files // and will be read in to populate the repository. Delta files begin with a header which must match the class definition. This is checked before loading the rest of the data. // If a file of the cache's name does not exist in the working directory, it will be created and a header will be written. // // If a backup directory has been specified and a file of the cache's name exists in this directory, the header will be checked and assuming this is OK, the length of the file // will aslo be checked (should match with that in the work directory) // // Arguments: None // // Returns: E_INITFAIL If Repository has no native data class, or the native data class has no members and/or no description // E_WRITEFAIL If the data file cannot be opened in write mode
_hzfunc("hdbObjRepos::InitDone") ;
const hdbMember* pMbr ; // Member ifstream is ; // For reading in working data file ofstream os ; // For writing in working data file FSTAT fs ; // File status hzChain E ; // Existing class description header from data file hzAtom atom ; // For setting member values hdbIndex* pIdx ; // The index to be added hdbIndexUkey* pIdxU ; // The index to be added hzString strDesc ; // Temp string holding memeber data uint32_t nLine ; // Line number for reporting file errors uint32_t mbrNo ; // Member number char* lineBuf ; // For getline hzEcode rc ; // Return code
// Check initialization and if there are some members added _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_INIT_PROG) ;
if (!m_pClass) return hzerr(E_INITFAIL, "Repository %s: No data class", *m_Name) ; if (!m_pClass->MbrCount()) return hzerr(E_INITFAIL, "Data class %s: No members!", *m_Name) ;
// Create the XML Class Description // m_pClass->DescClass(X, 0) ; // if (!X.Size()) // return hzerr(E_INITFAIL, "Data class %s: Failed to write description", *m_Name) ; // threadLog("Called with name %s and workdir %s\n", *m_Name, *m_Workdir) ;
if (m_pathCD) { // Cache and cache delta applies if (lstat(*m_pathCD, &fs) < 0) { // Working data file does not exist or is empty. Create a new one from the class description as per C++ calls os.open(*m_pathCD) ; if (os.fail()) return hzerr(E_WRITEFAIL, "Data class %s Cannot open data file %s in write mode", *m_Name, *m_pathCD) ;
os << m_pClass->Desc() ; if (os.fail()) { os.close() ; os.clear() ; hzerr(rc, "Data class %s Cannot write class description to data file %s", *m_Name, *m_pathCD) ; return rc ; } os.flush() ; os.close() ; os.clear() ; }
// Working data file does exist and has content so read it in. Start with header is.open(*m_pathCD) ; if (is.fail()) return hzerr(E_OPENFAIL, "Class %s data file %s exists but cannot be read in", *m_Name, *m_pathCD) ; lineBuf = new char[512] ; for (nLine = 1 ;; nLine++) { is.getline(lineBuf, 500) ; if (!lineBuf[0]) break ;
E << lineBuf ; E.AddByte(CHAR_NL) ;
if (!strcmp(lineBuf, "</class>")) break ; } is.close() ; delete lineBuf ;
// Compare class description header from file to that of the class strDesc = E ; if (strDesc != m_pClass->Desc()) hzerr(E_FORMAT, "Format error in data file %s. Existing description \n[\n%s\n]\nNew\n[\n%s\n]\n", *m_pathCD, *strDesc, *m_pClass->Desc()) ; }
// Initialize all allocated indexes for (mbrNo = 0 ; mbrNo < m_pClass->MbrCount() ; mbrNo++) { pMbr = m_pClass->GetMember(mbrNo) ; threadLog("Initializing member %s:%s\n", m_pClass->txtName(), pMbr->txtName()) ;
// Check if the member has an associated index pIdx = m_mapIndex[pMbr->DeltaId()] ; if (!pIdx) continue ;
if (pIdx->Whatami() == HZINDEX_UKEY) { pIdxU = (hdbIndexUkey*) pIdx ;
rc = pIdxU->Init(this, pMbr->strName(), pMbr->Basetype()) ;
if (rc != E_OK) return hzerr(rc, "Failed to initialize unique-key index %s (%s)\n", *m_Name, pMbr->txtName()) ; } }
// Init matrix
if (rc != E_OK) threadLog("Failed to init repos %s\n", *m_Name) ; else { threadLog("Complete init repos %s\n", *m_Name) ; m_eReposInit = HDB_REPOS_INIT_DONE ; } return rc ; }
const hdbObjRepos* hdbObjRepos::ObjRepos (const hdbMember* pMbr) const { // Locate the external repository associated with a subclass member. This will either be the repository itself or that specified during initialization InitMbrRepos() // // Argument: pMbr Data class member // // Returns: Pointer to the external repository if found, 0 otherwise
_hzfunc("hdbObjRepos::ObjRepos") ;
const hdbObjRepos* pR ; // Binary repos
if (!m_pClass) { hzerr(E_NOINIT, "No data class") ; return 0 ; } if (!pMbr) { hzerr(E_NOINIT, "No member supplied") ; return 0 ; }
if (pMbr->Class() != m_pClass) { hzerr(E_CORRUPT, "Member %s not in class %s", pMbr->txtName(), m_pClass->txtName()) ; return 0 ; }
if (pMbr->Basetype() != BASETYPE_CLASS) { hzerr(E_TYPE, "Member %s is not BINARY or TXTDOC", pMbr->txtName()) ; return 0 ; }
pR = m_mapRepos[pMbr->Posn()] ; if (!pR) return this ; return pR ; }
/* ** Open Repository. Support functions */
hzEcode hdbObjRepos::_loadCache (void) { // Load whole object deltas
_hzfunc("hdbObjRepos::_loadCache") ;
hdbObject currObj ; // Current object hzChain mlText ; // For gathering text content accross several lines hzChain edo ; // For EDO commital uint32_t objId ; // Object id hzEcode rc = E_OK ; // Return code
// Check init state _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_INIT_DONE) ;
// Init data object container rc = currObj.Init(m_pClass) ; if (rc != E_OK) return hzerr(E_NOINIT, "Could not init object") ;
// Check if RAM Primacy is deployed if (!m_pMain) return E_OK ; if (!m_pBR_Delta) return hzerr(E_NOINIT, "No binary repos for whole object deltas") ;
threadLog("CALLED on repos %s, binary repos %s\n", *m_Name, *m_nameBR_Delta) ;
for (objId = 1 ; objId < m_pBR_Delta->Count() && rc == E_OK ; objId++) { rc = m_pBR_Delta->Fetch(mlText, objId) ; if (rc != E_OK) { threadLog("Could not fetch object %u, err=%s\n", objId, Err2Txt(rc)) ; continue ; }
rc = currObj.ImportDelta(mlText) ; if (rc != E_OK) hzerr(rc, "Could not load full delta") ; else { rc = currObj.Integrity() ; if (rc != E_OK) hzerr(rc, "Case 1 Cannot Insert Object (Integrity fails)") ; else { rc = currObj.ExportEDO(edo) ; if (rc != E_OK) hzerr(rc, "Could not export EDO") ; else { rc = m_pMain->CommitEDO(edo, currObj.GetObjId(), true) ; if (rc != E_OK) hzerr(rc, "Could not commit EDO") ; else { rc = _updateIdx(currObj) ; if (rc != E_OK) hzerr(rc, "Could not update indexes") ; } } } }
currObj.Clear() ; mlText.Clear() ; }
m_nSeqId = m_nPopulation = m_pMain->Count() ;
threadLog("Population of objects in cache %s is %d. Status is %s\n", txtName(), Count(), Err2Txt(rc)) ; return rc ; }
hzEcode hdbObjRepos::_loadDeltas (void) { // Load data from delta files. // // Loads both whole object and member deltas. Note that member deltas are ignored unless the host object exists within the repository.
_hzfunc("hdbObjRepos::_loadDeltas") ;
ifstream is ; // For reading in working data file hdbObject currObj ; // Current object hzChain mlText ; // For gathering text content accross several lines hzChain Y ; // For writing class description header from data file hzChain edo ; // For EDO commital hzAtom atom ; // For setting member values _atomval av ; // Atom value const hdbMember* pMbr ; // Member hdbIndex* pIdx ; // Index pointer hdbIndexUkey* pIdxU ; // Index pointer hdbIndexEnum* pIdxE ; // Index pointer char* lineBuf ; // For getline char* j ; // For buffer iteration hzString tmpStr ; // Temp string holding memeber data hzDomain dom ; // Temp domain hzEmaddr ema ; // Temp email addr hzUrl url ; // Temp URL uint32_t nLine ; // Line number for reporting file errors uint32_t reposId ; // Repos id uint32_t classId ; // Class id uint32_t objId ; // Object id uint32_t lastObjId ; // Last object id uint32_t novals ; // Number of member values uint32_t mbrNo ; // Member number hzEcode rc = E_OK ; // Return code
// Check init state _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_INIT_DONE) ;
// Init data object container rc = currObj.Init(m_pClass) ; if (rc != E_OK) return hzerr(E_NOINIT, "Could not init object") ;
// Check if RAM Primacy is deployed if (!m_pMain) return E_OK ;
threadLog("CALLED on repos %s, delta file %s\n", *m_Name, *m_pathCD) ;
// Allocate line buffer lineBuf = new char[2048] ;
reposId = classId = objId = lastObjId = 0 ;
// Bypass header is.open(*m_pathCD) ; for (nLine = 1 ;; nLine++) { is.getline(lineBuf, 2040) ; if (!is.gcount()) break ;
if (is.gcount() == 2040) { rc = hzerr(E_RANGE, "Line %u exceeds buffer", nLine) ; break ; } lineBuf[is.gcount()] = 0 ;
Y << lineBuf ; Y.AddByte(CHAR_NL) ;
if (!strcmp(lineBuf, "</class>")) break ; }
// Now read in the rest of the data (in delta notation) threadLog("LOAD on repos %s, workpath %s\n", *m_Name, *m_pathCD) ;
lastObjId = 0 ; novals = 0 ; for (; rc == E_OK ; nLine++) { if (!(nLine % 1000)) threadLog("Processing line %u\n", nLine) ;
is.getline(lineBuf, 2040) ; if (!is.gcount()) { threadLog("Terminating on line %u\n", nLine) ; break ; }
if (is.gcount() == 2040) { rc = hzerr(E_RANGE, "Line %u exceeds buffer", nLine) ; break ; } lineBuf[is.gcount()] = 0 ;
if (lineBuf[0] == CHAR_AT) { if (!memcmp(lineBuf, "@obj", 4)) { // Whole form delta mlText << lineBuf ; mlText.AddByte(CHAR_NL) ; for (;; nLine++) { is.getline(lineBuf, 2040) ; if (!is.gcount()) break ; lineBuf[is.gcount()] = 0 ;
mlText << lineBuf ; mlText.AddByte(CHAR_NL) ;
if (lineBuf[0] == '}' && lineBuf[1] == 0) break ; }
rc = currObj.ImportDelta(mlText) ; if (rc != E_OK) hzerr(rc, "Could not load full delta") ; else { rc = currObj.Integrity() ; if (rc != E_OK) hzerr(rc, "Cannot Insert Object (Integrity fails)") ; else { rc = currObj.ExportEDO(edo) ; if (rc != E_OK) hzerr(rc, "Could not export EDO") ; else { rc = m_pMain->CommitEDO(edo, currObj.GetObjId(), true) ; if (rc != E_OK) hzerr(rc, "Could not commit EDO") ; else { rc = _updateIdx(currObj) ; if (rc != E_OK) hzerr(rc, "Could not update indexes") ; } } } }
currObj.Clear() ; mlText.Clear() ; novals = 0 ; continue ; }
// Handle partial deltas j = lineBuf + 1 ;
// Gather repos id if (*j == 'r') { for (j++, reposId = 0 ; IsDigit(*j) ; j++) { reposId *= 10 ; reposId += *j - '0' ; }
if (*j != CHAR_PERIOD) { rc = hzerr(E_FORMAT, "File %s Line %d: Period expected after repos ID", *m_pathCD, nLine) ; break ; } j++ ; }
// Gather class id if (*j == 'c') { for (j++, classId = 0 ; IsDigit(*j) ; j++) { classId *= 10 ; classId += *j - '0' ; }
if (*j != CHAR_PERIOD) { rc = hzerr(E_FORMAT, "File %s Line %d: Period expected after class ID", *m_pathCD, nLine) ; break ; } j++ ; }
// Gather and act on the object id in the delta if (*j == 'o') { for (j++, objId = 0 ; IsDigit(*j) ; j++) { objId *= 10 ; objId += *j - '0' ; } if (!lastObjId) lastObjId = objId ;
if (*j != CHAR_PERIOD) { rc = hzerr(E_FORMAT, "File %s Line %d: Period and member ID expected after object ID", *m_pathCD, nLine) ; break ; } j++ ;
if (lastObjId && objId != lastObjId) { // Now dealing with another object, so write out the EDO for the existing object, and start a new one // currObj.ExportDelta(J) ; rc = currObj.Integrity() ; if (rc != E_OK) { hzerr(rc, "Case 2 Cannot Insert Object - Integrity fails") ; break ; }
currObj.SetObjId(lastObjId) ; rc = currObj.ExportEDO(edo) ; if (rc != E_OK) hzerr(rc, "Could not export EDO") ; else { rc = m_pMain->CommitEDO(edo, lastObjId, true) ; if (rc != E_OK) hzerr(rc, "Could not commit EDO") ; }
if (rc != E_OK) break ;
currObj.Clear() ; lastObjId = objId ; novals = 0 ; //threadLog("Cleared object: ID %u\n", objId) ; } }
// Gather and act on the member ID in the delta if (*j == 'm') { for (j++, mbrNo = 0 ; IsDigit(*j) ; j++) { mbrNo *= 10 ; mbrNo += *j - '0' ; }
pMbr = m_pClass->GetMember(mbrNo) ; if (!pMbr) { rc = hzerr(E_FORMAT, "File %s Line %d: Member %d does not exist in class %s\n", *m_pathCD, nLine, mbrNo, m_pClass->txtType()) ; break ; }
//threadLog("Doing member %s\n", pMbr->txtName()) ; }
// Get member values if (*j == CHAR_EQUAL) { // Read in value (multi-line if applicable) tmpStr.Clear() ; j++ ; if (*j == CHAR_SQOPEN && j[1] == 0) { // Multi-line value. Loop with getline until a line is found with a ']' by itself. mlText.Clear() ; for (;;) { is.getline(lineBuf, 2040) ; if (!is.gcount()) break ;
lineBuf[is.gcount()] = 0 ;
if (lineBuf[0] == CHAR_SQCLOSE && lineBuf[1] == 0) break ;
mlText.Append(lineBuf, is.gcount()) ; }
if (!mlText.Size()) continue ; tmpStr = mlText ; } else { tmpStr = j ; } novals++ ;
if (!tmpStr) continue ;
// Set the member value in the object rc = atom.SetValue(pMbr->Basetype(), tmpStr) ; if (rc != E_OK) { threadLog("ERROR: Object %d member %s value %s. Err=%s\n", objId, pMbr->txtName(), *tmpStr, Err2Txt(rc)) ; break ; }
// if (pMbr->Basetype() == BASETYPE_XDATE) // threadLog("DELTA: Object %d member %s=%s (%s)\n", objId, pMbr->txtName(), atom.Show(), j) ;
rc = currObj.SetValue(pMbr, atom) ; if (rc != E_OK) { threadLog("ERROR - Could not set member %s\n", pMbr->txtName()) ; break ; }
pIdx = m_mapIndex[pMbr->DeltaId()] ; if (pIdx) { if (pIdx->Whatami() == HZINDEX_UKEY) { pIdxU = (hdbIndexUkey*) pIdx ; rc = pIdxU->Insert(atom, objId) ; if (rc != E_OK) { threadLog("Mbr %s Failed on UKEY index insert. Atom %s Err=%s\n", pMbr->txtName(), atom.Show(), Err2Txt(rc)) ; break ; } }
if (pIdx->Whatami() == HZINDEX_ENUM) { pIdxE = (hdbIndexEnum*) pIdx ; rc = pIdxE->Insert(objId, atom) ; if (rc != E_OK) { threadLog("Mbr %s Failed on ENUM index insert. Atom %s\n", pMbr->txtName(), atom.Show()) ; } } }
atom.Clear() ; }
continue ; }
hzerr(E_SYNTAX, "File %s Line %d [%s]: Unknown instruction. Only @obj:, @del:, and @obj: allowed\n", *m_pathCD, nLine, lineBuf) ; rc = E_SYNTAX ; break ; } is.close() ; threadLog("Delta file closed\n") ;
if (novals && rc == E_OK) { // Commit the last EDO rc = currObj.Integrity() ; if (rc != E_OK) hzerr(rc, "Case 3 Cannot Insert Object - Integrity fails") ; else { currObj.SetObjId(objId) ; rc = currObj.ExportEDO(edo) ; if (rc != E_OK) hzerr(rc, "Could not export EDO") ; else { rc = m_pMain->CommitEDO(edo, objId, true) ; if (rc != E_OK) hzerr(rc, "Could not commit EDO") ; } } }
m_nSeqId = m_nPopulation = m_pMain->Count() ;
threadLog("Population of objects in cache %s is %d. Delta file %s. Status is %s\n", txtName(), Count(), *m_pathCD, Err2Txt(rc)) ; delete [] lineBuf ; return rc ; }
hzEcode hdbObjRepos::Open (void) { // Open the data object repository, i.e. ready it for data operations. Depending on repository configuration, this action will do the following:- // // Open the binary repository for Whole Object Deltas. This is done in all cases. // This action restores RAM Primacy components to the last known data state. // // Now deal with files if the working directory has been supplied. If a file of the cache's name exists in the working directory, this is assumed // to be the data file and will be read in to populate the cache. The file must begin with a header which must match the class definition so this // is checked before loading the remaining data. If a file of the cache's name does not exist in the working directory, it will be created and a // header will be written. // // If a backup directory has been specified and a file of the cache's name exists in this directory, the header will be checked and assuming this // is OK, the length of the file will aslo be checked (should match with that in the work directory) // // Arguments: None
_hzfunc("hdbObjRepos::Open") ;
hzEcode rc ; // Return code
if (!this) Fatal("No instance") ; _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_INIT_DONE) ;
//if (!m_Workdir) // return hzerr(E_NOINIT, "No workdir") ;
if (m_pBR_Datum) { // Only if native class has BINARY/TXTDOC members rc = m_pBR_Datum->Open() ; if (rc != E_OK) return hzerr(E_NOINIT, "Could not open mbr datum binary repos") ; }
if (m_pBR_Delta) { rc = m_pBR_Delta->Open() ; if (rc != E_OK) return hzerr(E_NOINIT, "Could not open delta binary repos") ;
rc = _loadCache() ; threadLog("Whole Object Deltas loaded - Status %s\n", Err2Txt(rc)) ; }
rc = _loadDeltas() ; threadLog("Deltas loaded\n") ;
// Now open file for writing if (rc == E_OK) { m_osDelta.open(*m_pathCD, ios::app) ; if (m_osDelta.fail()) return hzerr(E_WRITEFAIL, "Class %s Cannot open data file %s in write mode", *m_Name, *m_pathCD) ; m_eReposInit = HDB_REPOS_OPEN ; }
threadLog("Population of objects in repos %s is %d. Delta file %s. Status %s\n", txtName(), Count(), *m_pathCD, Err2Txt(rc)) ; //threadLog("Repos %s: Pop %d\n", *m_Name, Count()) ; return rc ; }
hzEcode hdbObjRepos::Clear (void) { // Destroys all data in the Ram table and re-initializes everything. // // Arguments: None
_hzfunc("hdbObjRepos::Clear") ;
_hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_OPEN) ;
if (m_pMain) m_pMain->Clear() ; // if (m_pAuxA) m_pAuxA->Clear() ; // if (m_pAuxB) m_pAuxB->Clear() ;
return E_OK ; }
hzEcode hdbObjRepos::_updateIdx (const hdbObject& obj) { // Supprt function. Updates the repository indexes on behalf of Insert() and _loadDeltas()
_hzfunc("hdbObjRepos::_updateIdx") ;
const hdbMember* pMbr ; // Member pointer hdbIndex* pIdx ; // Index pointer hdbIndexUkey* pIdxU ; // Index pointer hdbIndexEnum* pIdxE ; // Index pointer hzAtom atom ; // Atom from member of populating object uint32_t objId ; // Object id uint32_t mbrNo ; // Member number hzEcode rc = E_OK ; // Return value hzEcode ic = E_OK ; // Return value
objId = obj.GetObjId() ; if (!objId) return hzerr(E_NOTFOUND, "No object id") ;
for (mbrNo = 0 ; mbrNo < m_pClass->MbrCount() ; mbrNo++) { // Get member and value pMbr = m_pClass->GetMember(mbrNo) ; obj.GetValue(atom, pMbr) ;
if (atom.IsNull()) continue ;
// Check if member has an index pIdx = m_mapIndex[pMbr->DeltaId()] ; if (!pIdx) continue ;
// Update index if (pIdx->Whatami() == HZINDEX_UKEY) { pIdxU = (hdbIndexUkey*) pIdx ; rc = pIdxU->Insert(atom, objId) ; }
if (pIdx->Whatami() == HZINDEX_ENUM) { pIdxE = (hdbIndexEnum*) pIdx ; rc = pIdxE->Insert(objId, atom) ; }
if (rc != E_OK) { threadLog("UKEY idx insert of %s returned err=%s\n", atom.Show(), Err2Txt(ic)) ; break ; } }
return rc ; }
hzEcode hdbObjRepos::Insert (uint32_t& objId, const hdbObject& theObj) { // The INSERT operation adds a new data object to a repository and creates a new object id in respect of it. If any indexes apply, these are updated accordingly. // // Note that in INSERT operations, the supplied object is expected to be an entirely new, and whole, object of the repository native data class. All subclass objects will have // been added to the native class data object, prior to this function call. Because the supplied data object is entirely new, a whole object delta is generated. // // In all cases the new data object is committed to a binary datum repository as a whole object delta. If RAM Primacy applies, the new data object is also written as an EDO to // repository cache. The whole object delta is produced by calling ExportDelta() on the supplied object. The EDO is produced by calling ExportEDO() on the supplied object. // // If the object has populated BINARY or TXTDOC members, their values are committed to the applicable binary datum repository before the delta and EDO exports. This is so that // the values are assigned datum ids - which are the only representation the values will have in the delta and in the EDO. // // Arguments: 1) objId The object id that will be assigned by this operation // 2) pObj Pointer to object to be inserted // // Returns: E_NOINIT If either the cache or the supplied object is not initialized // E_ARGUMENT If the object is not supplied // E_TYPE If the object is not of the same data class as the cache // E_DUPLICATE If the object cannot be inserted because one or more members violate uniqueness // E_WRITEFAIL If the object deltas cannot be written // E_OK If the insert operation was successful
_hzfunc("hdbObjRepos::Insert") ;
const hdbMember* pMbr ; // Member pointer
hzChain Z ; // For building output to data file hzChain theChain ; // For extracting atom data stored as chains hzChain edo ; // For EDO export and commital hzChain delta ; // For delta export hzAtom atom ; // Atom from member of populating object _atomval av ; // Atomic value hdbIndex* pIdx ; // Index pointer hdbIndexUkey* pIdxU ; // Index pointer //hdbIndexEnum* pIdxE ; // Index pointer hzString strVal ; // Temp string uint32_t mbrNo ; // Member number hzEcode rc = E_OK ; // Return value
// Check Init state if (!this) Fatal("No Object\n") ;
objId = 0 ; _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_OPEN) ;
if (!theObj.Class()) return hzerr(E_NOINIT, "Supplied object is not initialized") ;
// Check object class is the same as the host class or contains a sub-class that is the same as the sub-class if (theObj.Class() != m_pClass) { if (!m_pADP->IsSubClass(m_pClass, theObj.Class())) { hzerr(E_TYPE, "Supplied object class %s not compatible with this cache class %s", theObj.Classname(), m_pClass->txtType()) ; return E_TYPE ; } }
// For an INSERT the object id (in the supplied object), must be 0 if (theObj.GetObjId() != 0) return hzerr(E_RANGE, "Supplied object has an object id of %u", theObj.GetObjId()) ;
/* ** Check members to see if any of them require unique values. Any that do will have an unique key index. If the member value already exists, abort the INSERT. */
for (mbrNo = 0 ; mbrNo < m_pClass->MbrCount() ; mbrNo++) { pMbr = m_pClass->GetMember(mbrNo) ;
pIdx = m_mapIndex[pMbr->DeltaId()] ; if (!pIdx) continue ;
if (pIdx->Whatami() == HZINDEX_UKEY) { pIdxU = (hdbIndexUkey*) pIdx ; rc = theObj.GetValue(atom, pMbr) ;
//atom.SetValue(pMbr->Basetype(), theObj.m_Values[mbrNo]) ;
if (rc != E_OK) return hzerr(rc, "%s: Could not select on index for member %s", *m_Name, pMbr->txtName()) ;
if (objId) return hzerr(E_DUPLICATE, "%s: Got objId of %d for member %s", *m_Name, objId, pMbr->txtName()) ; } }
/* ** The new object does not conflict with an existing one and so insertation can proceed. The objId is assigned as the number of existing objects + 1 */
// Issue the object id objId = ++m_nSeqId ; theObj.SetObjId(objId) ;
// Commit BINARY/TXTDOC values if (m_pBR_Datum) { rc = theObj.CommitBinaries(m_pBR_Datum) ; if (rc != E_OK) return hzerr(rc, "Could not commit binaries") ; }
// Export whole object delta rc = theObj.ExportDelta(delta) ; if (rc != E_OK) return hzerr(rc, "Could not export whole object delta") ;
// Update the delta file m_osDelta << delta ; m_osDelta.flush() ;
// Commit whole object delta to binary datum repository if (m_pMain) { // Commit EDO rc = theObj.ExportEDO(edo) ; if (rc != E_OK) return hzerr(rc, "Could not export EDO") ;
// Commit EDO to cache rc = m_pMain->CommitEDO(edo, objId, false) ; if (rc != E_OK) return hzerr(rc, "Could not commit EDO") ; }
// Update indexes rc = _updateIdx(theObj) ; if (rc != E_OK) return hzerr(rc, "Could not update indexes") ; return rc ; }
hzEcode hdbObjRepos::Delete (uint32_t objId) { // Mark as deleted, the object found at the supplied address. Write out an object deletion to the working and backup data files is they apply. // // Arguments: 1) objId The target object id
_hzfunc("hdbObjRepos::Delete") ;
_hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_OPEN) ;
// if (!mx->m_Objects.Exists(objId)) // return E_NOTFOUND ;
//if (m_bDeletes) //return E_DELETE ;
// pOld = (char*) mx->m_Objects[objId] ;
// mx->m_Objects.Delete(objId) ;
return E_OK ; }
hzEcode hdbObjRepos::Update (hdbObject& obj, uint32_t objId) { // Overwrite the object found at the supplied address, with the supplied object and update any affected indexes accordingly // // Arguments: 1) obj The new version of the data object // 2) objId The object id of the original version // // DEPRECATED
_hzfunc("hdbObjRepos::Update") ;
uint32_t nIndex ; // Member and index iterator
_hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_OPEN) ;
if (objId >= m_pMain->Count()) return E_RANGE ;
// Now go thru object's class members filling in the allocated fixed length space for (nIndex = 0 ;; nIndex++) { }
return E_OK ; }
hzEcode hdbObjRepos::Fetch (hdbObject& obj, uint32_t objId) const { // Fetch populates the supplied object recipticle (hdbObject instance) with the object identified by the supplied object id. // // The supplied recepticle is cleared by this function. If the supplied object id is invalid, the recepticle is left blank // // Arguments: 1) obj The object // 2) objId The object id to fetch // // Returns: E_NOTFOUND The requested object does not exist or has been deleted // E_OK Operation success
_hzfunc("hdbObjRepos::Fetch") ;
hzChain edo ; // EDO fetched from repos and passed to object hzEcode rc = E_OK ; // Return code
// Check init state and that supplied object is of the same class as the cache _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_OPEN) ;
// Wrong data class? if (obj.Class() != m_pClass) hzexit(E_TYPE, "Repository %s is of class %s. Supplied object is of class %s", *m_Name, Classname(), obj.Classname()) ;
// Clear all object members obj.Clear() ;
// Object id out of range? if (objId > m_pMain->Count()) return hzerr(E_NOTFOUND, "Beyond Range %u\n", m_pMain->Count()) ;
// Fetch data object if (m_pMain) { // Fetch EDO rc = m_pMain->FetchEDO(edo, objId) ; if (rc != E_OK) { threadLog("FetchEDO failed\n") ; return rc ; }
rc = obj.ImportEDO(edo) ; if (rc != E_OK) { threadLog("ImportEDO failed\n") ; return rc ; }
rc = obj.Integrity() ; if (rc != E_OK) { hzChain err ; // Error chIter ei ; // EDO iterator
err << "EDO is [ " ; for (ei = edo ; !ei.eof() ; ei++) { err.Printf("%02x ", (uchar) *ei) ; } err << "]\n" ; threadLog(err) ; threadLog("Integrity check failed err=%s\n", Err2Txt(rc)) ; }
return rc ; }
// Fetch data object as whole object delta return rc ; }
hzEcode hdbObjRepos::Exists (uint32_t& objId, const hdbMember* pMbr, const hzAtom& value) { // Identify a single object by matching on the supplied member name and value. // // Arguments: 1) objId The object id identified by the operation (0 if not object found) // 2) pMbr The member to be tested // 3) value The value the member must have to identify the object // // Returns@ E_NOINIT If the object cache is not initialized // E_CORRUPT If the member does not exist within the cache data class // E_NODATA If the member is not indexed // E_OK If no errors occured
_hzfunc("hdbObjRepos::Exists()") ;
hdbIndex* pIdx ; // Index pointer hdbIndexUkey* pIdxU ; // Index pointer hzEcode rc ; // Return code
// No instance? if (!this) hzexit(E_CORRUPT, "No instance") ; threadLog("Called on member %s value %s\n", pMbr->txtName(), value.Show()) ;
// Check init state _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_OPEN) ;
if (!m_pClass) return hzerr(E_NOINIT, "No cache class set up") ; if (!pMbr) return hzerr(E_ARGUMENT, "No member supplied") ;
objId = 0 ;
// Check for index pIdx = m_mapIndex[pMbr->DeltaId()] ; if (!pIdx) return hzerr(E_NODATA, "No index on member %s in class %s", pMbr->txtName(), m_pClass->txtName()) ;
//atom.SetValue(pMbr->Basetype(), value) ;
if (pIdx->Whatami() != HZINDEX_UKEY) return hzerr(E_TYPE, "Wrong index on member %s in class %s", pMbr->txtName(), m_pClass->txtName()) ;
pIdxU = (hdbIndexUkey*) pIdx ; rc = pIdxU->Select(objId, value) ; if (rc != E_OK) return hzerr(rc, "ERROR: Index selection on member %s in class %s", pMbr->txtName(), m_pClass->txtName()) ; return rc ; }
#if 0 hzEcode hdbObjRepos::Fetchbin (hzAtom& atom, const hzString& member, uint32_t objId) { // Fetch the actual binary content from a document/binary member. This is a two step process. Firstly in the object element itself, we have the // address of the binary which will reside in a hdbBinCron or hdbBinStore instance. The Second part is lifting the actual value (reading in the // binary) // // Arguments: 1) atom The atom to be set to the member's value. // 2) member The name of member // 3) objId The id of the data object // // Returns: E_RANGE If the object id is invalid // E_TYPE If the member is not BASETYPE_BINARY or BASETYPE_TXTDOC // E_OK If the operation was successful
_hzfunc("hdbObjRepos::Fetchbin") ;
const hdbMember* pMbr ; // Member pointer const hdbBinRepos* pRepos ; // Applicabe binary datum repository hzChain Z ; // Chain to recieve the binary from the hdbBinCron _atomval av ; // Atom value uint32_t nSlot ; // Set by AssignSlot uint32_t mbrNo ; // Member position uint32_t addr ; // String number hzEcode rc = E_OK ; // Return from hdbBinCron::Fetch
atom.Clear() ;
_hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_OPEN) ;
pMbr = m_pClass->GetMember(member) ; if (!pMbr) return hzerr(E_CORRUPT, "No class member of %s in class %s", *member, m_pClass->txtType()) ; mbrNo = pMbr->Posn() ;
if (objId < 1 || objId > m_pMain->Count()) return E_RANGE ;
// And check member is a document or a binary if (pMbr->Basetype() != BASETYPE_BINARY && pMbr->Basetype() != BASETYPE_TXTDOC) return E_TYPE ;
// Grab the binary address from this object element m_pMain->AssignSlot(nSlot, objId, 0) ;
m_pMain->GetVal(av, objId, mbrNo) ; addr = av.m_uInt32 ;
// Grab the binary value //rc = m_Binaries[mbrNo]->Fetch(Z, addr) ; pRepos = (const hdbBinRepos*) m_pStores[mbrNo] ; rc = pRepos->Fetch(Z, addr) ; if (rc == E_OK) atom.SetValue(pMbr->Basetype(), Z) ;
return rc ; } #endif
hzEcode hdbObjRepos::GetBinary (hzChain& Z, const hdbMember* pMbr, uint32_t objId) const { // Populate the supplied chain with the binary object held by the named member in the identified data object. // // This assumes the named data class member holds binary objects and that the supplied data object id is valid. As object repositories do not directly hold // binary values, the member value will be the address of the binary object residing in a separate binary repository. The address is then used in a Fetch() // on the binary repository. // // Arguments: 1) atom The atom to be set to the member's value. // 2) member The name of member // 3) objId The id of the data object // // Returns: E_RANGE If the object id is invalid // E_TYPE If the member is not BASETYPE_BINARY or BASETYPE_TXTDOC // E_OK If the operation was successful
_hzfunc("hdbObjRepos::GetBinary") ;
// Exit if cache not open _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_OPEN) ;
if (!pMbr) return hzerr(E_ARGUMENT, "No member supplied") ; if (pMbr->Class() != m_pClass) return hzerr(E_CORRUPT, "No class member of %s in class %s", pMbr->txtName(), m_pClass->txtType()) ;
// And check member is a document or a binary if (pMbr->Basetype() != BASETYPE_BINARY && pMbr->Basetype() != BASETYPE_TXTDOC) return E_TYPE ;
// Grab the binary value return m_pBR_Datum->Fetch(Z, objId) ; }
#if 0 hzEcode hdbObjRepos::Fetchlist (hzVect<uint32_t>& items, const hzString& member, uint32_t objId) { // For members that amount to lists (of either atomic values or class instances), fetch the list into the supplied vector (of uint32_t). The vector // will then be used to iterate through real values for the member, stored in one of the auxillary RAM tables. // // Arguments: 1) items The vector of items (uint32_t) which will serve as addresses // 2) member The class member (which must be defined as supporting multiple values) // 3) objId The data object id // // Returns: E_NOINIT If the hdbObjRepos is not fully initialized // E_CORRUPT If the named member does not exist // E_RANGE If the member is not a list (has max pop of 1) // E_NOTFOUND If the object id does not exist in the repository // E_OK If init state is full, member is a list and object exists - even if the member has no values.
_hzfunc("hdbObjRepos::Fetchlist") ;
const hdbMember* pMbr ; // Member pointer
items.Clear() ;
_hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_OPEN) ;
pMbr = m_pClass->GetMember(member) ; if (!pMbr) return hzerr(E_CORRUPT, "No class member of %s in class %s", *member, m_pClass->txtType()) ;
if (pMbr->MaxPop() == 1) return E_RANGE ;
if (objId < 1 || objId > m_pMain->Count()) return E_NOTFOUND ;
// if (!mx->m_Lists[pMbr->Posn()]) // return E_TYPE ; return E_OK ; } #endif
hzEcode hdbObjRepos::Select (hdbIdset& result, const char* cpSQL) const { // Select data objects according to the supplied search criteria (arg 2), and populate the supplied hdbIdset with the object ids. // // The parse process is rudimentary, so SQL-esce rather than strict SQL. Each search criteria term will produce an idset result. OR and AND operations are applied where there // are multiple terms. If these operations are not stated, AND is assumed. // // Arguments: 1) result The bitmap of object ids identified by the select operation // 2) cpSql The SQL-esce search criteria
_hzfunc("hdbObjRepos::Select_a") ;
hzEcode rc = E_OK ;
// Check init state _hdb_ck_initstate(m_Name, m_eReposInit, HDB_REPOS_OPEN) ;
// Clear result idset result.Clear() ;
// Do the Select
// if (!pExp->Parse(cpSQL)) // hzerr(E_PARSE) ;
return rc ; }