aqhome: make datafile a virtual class. Add datafile_direct.
this is to allow for cached data file handling later.
This commit is contained in:
@@ -30,6 +30,7 @@
|
|||||||
<setVar name="local/typefiles" >
|
<setVar name="local/typefiles" >
|
||||||
value.t2d
|
value.t2d
|
||||||
device.t2d
|
device.t2d
|
||||||
|
datafile.t2d
|
||||||
</setVar>
|
</setVar>
|
||||||
|
|
||||||
<setVar name="local/built_sources" >
|
<setVar name="local/built_sources" >
|
||||||
@@ -56,7 +57,7 @@
|
|||||||
|
|
||||||
<headers dist="true" install="$(pkgincludedir)/data" >
|
<headers dist="true" install="$(pkgincludedir)/data" >
|
||||||
storage.h
|
storage.h
|
||||||
datafile.h
|
datafile_direct.h
|
||||||
</headers>
|
</headers>
|
||||||
|
|
||||||
|
|
||||||
@@ -64,7 +65,7 @@
|
|||||||
storage_p.h
|
storage_p.h
|
||||||
storage_readxml.h
|
storage_readxml.h
|
||||||
storage_writexml.h
|
storage_writexml.h
|
||||||
datafile_p.h
|
datafile_direct_p.h
|
||||||
</headers>
|
</headers>
|
||||||
|
|
||||||
|
|
||||||
@@ -74,7 +75,7 @@
|
|||||||
storage.c
|
storage.c
|
||||||
storage_readxml.c
|
storage_readxml.c
|
||||||
storage_writexml.c
|
storage_writexml.c
|
||||||
datafile.c
|
datafile_direct.c
|
||||||
</sources>
|
</sources>
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -1,401 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project Gwenhywfar.
|
|
||||||
* Gwenhywfar (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifdef HAVE_CONFIG_H
|
|
||||||
# include <config.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "./datafile_p.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/debug.h>
|
|
||||||
#include <gwenhywfar/syncio_file.h>
|
|
||||||
|
|
||||||
#include <unistd.h>
|
|
||||||
|
|
||||||
|
|
||||||
GWEN_LIST_FUNCTIONS(AQH_DATAFILE, AQH_DataFile);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* forward declarations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
|
|
||||||
static int _readRecord(GWEN_SYNCIO *sio, uint64_t idx, uint64_t *pTimestamp, double *pValue);
|
|
||||||
static int _writeRecord(GWEN_SYNCIO *sio, uint64_t filePos, uint64_t timestamp, double value);
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/* ------------------------------------------------------------------------------------------------
|
|
||||||
* implementations
|
|
||||||
* ------------------------------------------------------------------------------------------------
|
|
||||||
*/
|
|
||||||
|
|
||||||
AQH_DATAFILE *AQH_DataFile_new(const char *fileName, uint64_t valueId)
|
|
||||||
{
|
|
||||||
AQH_DATAFILE *df;
|
|
||||||
|
|
||||||
GWEN_NEW_OBJECT(AQH_DATAFILE, df);
|
|
||||||
GWEN_LIST_INIT(AQH_DATAFILE, df);
|
|
||||||
df->valueId=valueId;
|
|
||||||
df->fileName=fileName?strdup(fileName):NULL;
|
|
||||||
|
|
||||||
return df;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void AQH_DataFile_free(AQH_DATAFILE *df)
|
|
||||||
{
|
|
||||||
if (df) {
|
|
||||||
GWEN_LIST_FINI(AQH_DATAFILE, df);
|
|
||||||
GWEN_SyncIo_free(df->sio);
|
|
||||||
free(df->fileName);
|
|
||||||
GWEN_FREE_OBJECT(df);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
const char *AQH_DataFile_GetFileName(const AQH_DATAFILE *df)
|
|
||||||
{
|
|
||||||
return df?df->fileName:NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint64_t AQH_DataFile_GetValueId(const AQH_DATAFILE *df)
|
|
||||||
{
|
|
||||||
return df?df->valueId:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint64_t AQH_DataFile_GetNumberOfEntries(const AQH_DATAFILE *df)
|
|
||||||
{
|
|
||||||
return df?df->numberOfEntries:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
uint32_t AQH_DataFile_GetRuntimeFlags(const AQH_DATAFILE *df)
|
|
||||||
{
|
|
||||||
return df?df->runtimeFlags:0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AQH_DataFile_Create(AQH_DATAFILE *df)
|
|
||||||
{
|
|
||||||
if (df) {
|
|
||||||
GWEN_SYNCIO *sio;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
if (df->sio) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "File already open");
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
sio=GWEN_SyncIo_File_new(df->fileName, GWEN_SyncIo_File_CreationMode_CreateNew);
|
|
||||||
GWEN_SyncIo_SetFlags(sio,
|
|
||||||
GWEN_SYNCIO_FILE_FLAGS_WRITE | GWEN_SYNCIO_FILE_FLAGS_READ |
|
|
||||||
GWEN_SYNCIO_FILE_FLAGS_UREAD | GWEN_SYNCIO_FILE_FLAGS_UWRITE);
|
|
||||||
rv=GWEN_SyncIo_Connect(sio);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error creating file \"%s\" (%d)", df->fileName, rv);
|
|
||||||
GWEN_SyncIo_free(sio);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
rv=_writeRecord(sio, 0, 0, 0.0);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_DEBUG(AQH_LOGDOMAIN, "Error adding first record to file \"%s\" (%d)", df->fileName, rv);
|
|
||||||
GWEN_SyncIo_free(sio);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
df->sio=sio;
|
|
||||||
df->numberOfEntries=1; /* we just added the 0-record */
|
|
||||||
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "File \"%s\" created.", df->fileName);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Nullpointer");
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AQH_DataFile_Open(AQH_DATAFILE *df)
|
|
||||||
{
|
|
||||||
if (df) {
|
|
||||||
GWEN_SYNCIO *sio;
|
|
||||||
int rv;
|
|
||||||
int64_t len;
|
|
||||||
|
|
||||||
if (df->sio) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "File already open");
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
sio=GWEN_SyncIo_File_new(df->fileName, GWEN_SyncIo_File_CreationMode_OpenExisting);
|
|
||||||
GWEN_SyncIo_SetFlags(sio, GWEN_SYNCIO_FILE_FLAGS_WRITE | GWEN_SYNCIO_FILE_FLAGS_READ);
|
|
||||||
rv=GWEN_SyncIo_Connect(sio);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error opening file \"%s\" (%d)", df->fileName, rv);
|
|
||||||
GWEN_SyncIo_free(sio);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
len=GWEN_SyncIo_File_Seek(sio, 0, GWEN_SyncIo_File_Whence_End);
|
|
||||||
if (len<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error seeking to end of file \"%s\" (%d)", df->fileName, rv);
|
|
||||||
GWEN_SyncIo_free(sio);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
if (len % AQH_DATAFILE_RECORDSIZE) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Invalid file size of file \"%s\" (not a multiple of current record size)", df->fileName);
|
|
||||||
GWEN_SyncIo_Disconnect(sio);
|
|
||||||
GWEN_SyncIo_free(sio);
|
|
||||||
unlink(df->fileName);
|
|
||||||
return GWEN_ERROR_BAD_DATA;
|
|
||||||
}
|
|
||||||
df->numberOfEntries=len/AQH_DATAFILE_RECORDSIZE;
|
|
||||||
|
|
||||||
len=GWEN_SyncIo_File_Seek(sio, 0, GWEN_SyncIo_File_Whence_Set);
|
|
||||||
if (len<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error seeking to begin of file \"%s\" (%d)", df->fileName, rv);
|
|
||||||
GWEN_SyncIo_free(sio);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
df->sio=sio;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Nullpointer");
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AQH_DataFile_Close(AQH_DATAFILE *df)
|
|
||||||
{
|
|
||||||
if (df) {
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
if (df->sio==NULL) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "File not open");
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=GWEN_SyncIo_Disconnect(df->sio);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Error closing file \"%s\" (%d)", df->fileName, rv);
|
|
||||||
GWEN_SyncIo_free(df->sio);
|
|
||||||
df->sio=NULL;
|
|
||||||
df->numberOfEntries=0;
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
GWEN_SyncIo_free(df->sio);
|
|
||||||
df->sio=NULL;
|
|
||||||
df->numberOfEntries=0;
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Nullpointer");
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AQH_DataFile_ReadRecord(AQH_DATAFILE *df, uint64_t idx, uint64_t *pTimestamp, double *pValue)
|
|
||||||
{
|
|
||||||
if (df) {
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
if (df->sio==NULL) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "File not open");
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=_readRecord(df->sio, idx, pTimestamp, pValue);;
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error reading from file \"%s\" (%d)", df->fileName, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Nullpointer");
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int AQH_DataFile_AppendRecord(AQH_DATAFILE *df, uint64_t timestamp, double value)
|
|
||||||
{
|
|
||||||
if (df) {
|
|
||||||
int rv;
|
|
||||||
uint64_t filePos;
|
|
||||||
|
|
||||||
if (df->sio==NULL) {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "File not open");
|
|
||||||
return GWEN_ERROR_INVALID;
|
|
||||||
}
|
|
||||||
|
|
||||||
filePos=(df->numberOfEntries)*AQH_DATAFILE_RECORDSIZE;
|
|
||||||
rv=_writeRecord(df->sio, filePos, timestamp, value);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error writing to file \"%s\" (%d)", df->fileName, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
df->numberOfEntries++;
|
|
||||||
DBG_DEBUG(AQH_LOGDOMAIN, "File \"%s\" has now %lu entries", df->fileName, (unsigned long int) (df->numberOfEntries));
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
DBG_ERROR(AQH_LOGDOMAIN, "Nullpointer");
|
|
||||||
return GWEN_ERROR_GENERIC;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
AQH_DATAFILE *AQH_DataFile_List_GetByValueId(AQH_DATAFILE_LIST *fileList, uint64_t id)
|
|
||||||
{
|
|
||||||
if (fileList) {
|
|
||||||
AQH_DATAFILE *df;
|
|
||||||
|
|
||||||
df=AQH_DataFile_List_First(fileList);
|
|
||||||
while(df) {
|
|
||||||
if (df->valueId==id)
|
|
||||||
return df;
|
|
||||||
df=AQH_DataFile_List_Next(df);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _readRecord(GWEN_SYNCIO *sio, uint64_t idx, uint64_t *pTimestamp, double *pValue)
|
|
||||||
{
|
|
||||||
uint8_t record[AQH_DATAFILE_RECORDSIZE];
|
|
||||||
union {double f; uint64_t i;} u;
|
|
||||||
uint64_t filePos;
|
|
||||||
int64_t retPos;
|
|
||||||
const uint8_t *ptr;
|
|
||||||
uint64_t v;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
filePos=idx*AQH_DATAFILE_RECORDSIZE;
|
|
||||||
retPos=GWEN_SyncIo_File_Seek(sio, filePos, GWEN_SyncIo_File_Whence_Set);
|
|
||||||
if (retPos<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error seeking to pos %lu (%d)", (unsigned long int) filePos, (int) retPos);
|
|
||||||
return (int) retPos;
|
|
||||||
}
|
|
||||||
|
|
||||||
rv=GWEN_SyncIo_ReadForced(sio, record, AQH_DATAFILE_RECORDSIZE);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error reading at pos %lu (%d)", (unsigned long int) filePos, rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
|
|
||||||
ptr=record+AQH_DATAFILE_OFFSET_TIMESTAMP;
|
|
||||||
v=0;
|
|
||||||
v|=(uint64_t)(*(ptr++));
|
|
||||||
v|=(uint64_t)(*(ptr++))<<8;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<16;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<24;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<32;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<40;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<48;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<56;
|
|
||||||
*pTimestamp=v;
|
|
||||||
|
|
||||||
ptr=record+AQH_DATAFILE_OFFSET_VALUE;
|
|
||||||
v=0;
|
|
||||||
v|=(uint64_t)(*(ptr++));
|
|
||||||
v|=(uint64_t)(*(ptr++))<<8;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<16;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<24;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<32;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<40;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<48;
|
|
||||||
v|=(uint64_t)(*(ptr++))<<56;
|
|
||||||
u.i=v;
|
|
||||||
*pValue=u.f;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
int _writeRecord(GWEN_SYNCIO *sio, uint64_t filePos, uint64_t timestamp, double value)
|
|
||||||
{
|
|
||||||
uint8_t record[AQH_DATAFILE_RECORDSIZE];
|
|
||||||
union {double f; uint64_t i;} u;
|
|
||||||
uint8_t *ptr;
|
|
||||||
int64_t retPos;
|
|
||||||
uint64_t v;
|
|
||||||
int rv;
|
|
||||||
|
|
||||||
ptr=record+AQH_DATAFILE_OFFSET_TIMESTAMP;
|
|
||||||
v=timestamp;
|
|
||||||
*(ptr++)=(v) & 0xff;
|
|
||||||
*(ptr++)=(v>>8) & 0xff;
|
|
||||||
*(ptr++)=(v>>16) & 0xff;
|
|
||||||
*(ptr++)=(v>>24) & 0xff;
|
|
||||||
*(ptr++)=(v>>32) & 0xff;
|
|
||||||
*(ptr++)=(v>>40) & 0xff;
|
|
||||||
*(ptr++)=(v>>48) & 0xff;
|
|
||||||
*(ptr++)=(v>>56) & 0xff;
|
|
||||||
|
|
||||||
u.f=value;
|
|
||||||
v=u.i;
|
|
||||||
ptr=record+AQH_DATAFILE_OFFSET_VALUE;
|
|
||||||
*(ptr++)=(v) & 0xff;
|
|
||||||
*(ptr++)=(v>>8) & 0xff;
|
|
||||||
*(ptr++)=(v>>16) & 0xff;
|
|
||||||
*(ptr++)=(v>>24) & 0xff;
|
|
||||||
*(ptr++)=(v>>32) & 0xff;
|
|
||||||
*(ptr++)=(v>>40) & 0xff;
|
|
||||||
*(ptr++)=(v>>48) & 0xff;
|
|
||||||
*(ptr++)=(v>>56) & 0xff;
|
|
||||||
|
|
||||||
retPos=GWEN_SyncIo_File_Seek(sio, filePos, GWEN_SyncIo_File_Whence_Set);
|
|
||||||
if (retPos<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error seeking to pos %lu (%d)", (unsigned long int) filePos, (int) retPos);
|
|
||||||
return (int) retPos;
|
|
||||||
}
|
|
||||||
rv=GWEN_SyncIo_WriteForced(sio, record, AQH_DATAFILE_RECORDSIZE);
|
|
||||||
if (rv<0) {
|
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error writing to file (%d)", rv);
|
|
||||||
return rv;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,44 +0,0 @@
|
|||||||
/****************************************************************************
|
|
||||||
* This file is part of the project Gwenhywfar.
|
|
||||||
* Gwenhywfar (c) by 2023 Martin Preuss, all rights reserved.
|
|
||||||
*
|
|
||||||
* The license for this file can be found in the file COPYING which you
|
|
||||||
* should have received along with this file.
|
|
||||||
****************************************************************************/
|
|
||||||
|
|
||||||
#ifndef AQH_DATAFILE_H
|
|
||||||
#define AQH_DATAFILE_H
|
|
||||||
|
|
||||||
|
|
||||||
#include "aqhome/data/storage.h"
|
|
||||||
|
|
||||||
#include <gwenhywfar/list.h>
|
|
||||||
|
|
||||||
|
|
||||||
typedef struct AQH_DATAFILE AQH_DATAFILE;
|
|
||||||
GWEN_LIST_FUNCTION_LIB_DEFS(AQH_DATAFILE, AQH_DataFile, AQHOME_API)
|
|
||||||
|
|
||||||
|
|
||||||
AQHOME_API AQH_DATAFILE *AQH_DataFile_new(const char *fileName, uint64_t valueId);
|
|
||||||
AQHOME_API void AQH_DataFile_free(AQH_DATAFILE *df);
|
|
||||||
|
|
||||||
AQHOME_API int AQH_DataFile_Create(AQH_DATAFILE *df);
|
|
||||||
AQHOME_API int AQH_DataFile_Open(AQH_DATAFILE *df);
|
|
||||||
AQHOME_API int AQH_DataFile_Close(AQH_DATAFILE *df);
|
|
||||||
|
|
||||||
AQHOME_API const char *AQH_DataFile_GetFileName(const AQH_DATAFILE *df);
|
|
||||||
AQHOME_API uint64_t AQH_DataFile_GetValueId(const AQH_DATAFILE *df);
|
|
||||||
|
|
||||||
AQHOME_API uint64_t AQH_DataFile_GetNumberOfEntries(const AQH_DATAFILE *df);
|
|
||||||
|
|
||||||
AQHOME_API uint32_t AQH_DataFile_GetRuntimeFlags(const AQH_DATAFILE *df);
|
|
||||||
|
|
||||||
AQHOME_API int AQH_DataFile_ReadRecord(AQH_DATAFILE *df, uint64_t idx, uint64_t *pTimestamp, double *pValue);
|
|
||||||
AQHOME_API int AQH_DataFile_AppendRecord(AQH_DATAFILE *df, uint64_t timestamp, double value);
|
|
||||||
|
|
||||||
AQHOME_API AQH_DATAFILE *AQH_DataFile_List_GetByValueId(AQH_DATAFILE_LIST *fileList, uint64_t id);
|
|
||||||
|
|
||||||
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
154
aqhome/data/datafile.t2d
Normal file
154
aqhome/data/datafile.t2d
Normal file
@@ -0,0 +1,154 @@
|
|||||||
|
<?xml?>
|
||||||
|
|
||||||
|
<tm2>
|
||||||
|
<type id="AQH_DATAFILE" type="pointer">
|
||||||
|
<descr>
|
||||||
|
This class contains changelog information,
|
||||||
|
</descr>
|
||||||
|
<lang id="c">
|
||||||
|
<identifier>AQH_DATAFILE</identifier>
|
||||||
|
<prefix>AQH_DataFile</prefix>
|
||||||
|
<baseFileName>datafile</baseFileName>
|
||||||
|
|
||||||
|
<flags>
|
||||||
|
nocopy
|
||||||
|
nodup
|
||||||
|
with_inherit
|
||||||
|
with_list1
|
||||||
|
with_refcount
|
||||||
|
</flags>
|
||||||
|
|
||||||
|
<headers>
|
||||||
|
<header type="sys" loc="pre">aqhome/api.h</header>
|
||||||
|
</headers>
|
||||||
|
|
||||||
|
<inlines>
|
||||||
|
|
||||||
|
</inlines>
|
||||||
|
|
||||||
|
|
||||||
|
</lang>
|
||||||
|
|
||||||
|
|
||||||
|
<enums>
|
||||||
|
|
||||||
|
</enums>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<members>
|
||||||
|
|
||||||
|
<member name="valueId" type="uint64_t" maxlen="8">
|
||||||
|
<default>0</default>
|
||||||
|
<preset>0</preset>
|
||||||
|
<flags>with_getbymember</flags>
|
||||||
|
<access>public</access>
|
||||||
|
</member>
|
||||||
|
|
||||||
|
</members>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<virtualFns>
|
||||||
|
|
||||||
|
|
||||||
|
<!-- Database functions -->
|
||||||
|
|
||||||
|
<fn name="create" location="post" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
<access>public</access>
|
||||||
|
<returnType>int</returnType>
|
||||||
|
<defaultReturnValue>GWEN_ERROR_NOT_IMPLEMENTED</defaultReturnValue>
|
||||||
|
<params>
|
||||||
|
</params>
|
||||||
|
</fn>
|
||||||
|
|
||||||
|
|
||||||
|
<fn name="open" location="post" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
<access>public</access>
|
||||||
|
<returnType>int</returnType>
|
||||||
|
<defaultReturnValue>GWEN_ERROR_NOT_IMPLEMENTED</defaultReturnValue>
|
||||||
|
<params>
|
||||||
|
</params>
|
||||||
|
</fn>
|
||||||
|
|
||||||
|
|
||||||
|
<fn name="close" location="post" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
<access>public</access>
|
||||||
|
<returnType>int</returnType>
|
||||||
|
<defaultReturnValue>GWEN_ERROR_NOT_IMPLEMENTED</defaultReturnValue>
|
||||||
|
<params>
|
||||||
|
</params>
|
||||||
|
</fn>
|
||||||
|
|
||||||
|
<fn name="getNumberOfEntries" location="post" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
<access>public</access>
|
||||||
|
<returnType>uint64_t</returnType>
|
||||||
|
<defaultReturnValue>0</defaultReturnValue>
|
||||||
|
<params>
|
||||||
|
</params>
|
||||||
|
</fn>
|
||||||
|
|
||||||
|
<fn name="readRecord" location="post" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
<access>public</access>
|
||||||
|
<returnType>int</returnType>
|
||||||
|
<defaultReturnValue>GWEN_ERROR_NOT_IMPLEMENTED</defaultReturnValue>
|
||||||
|
<params>
|
||||||
|
|
||||||
|
<param type="uint64_t" name="idx" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
</param>
|
||||||
|
|
||||||
|
<param type="uint64_t*" name="pTimestamp" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
</param>
|
||||||
|
|
||||||
|
<param type="double*" name="pValue" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
</param>
|
||||||
|
|
||||||
|
</params>
|
||||||
|
</fn>
|
||||||
|
|
||||||
|
|
||||||
|
<fn name="appendRecord" location="post" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
<access>public</access>
|
||||||
|
<returnType>int</returnType>
|
||||||
|
<defaultReturnValue>GWEN_ERROR_NOT_IMPLEMENTED</defaultReturnValue>
|
||||||
|
<params>
|
||||||
|
|
||||||
|
<param type="uint64_t" name="timestamp" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
</param>
|
||||||
|
|
||||||
|
<param type="double" name="value" >
|
||||||
|
<descr>
|
||||||
|
</descr>
|
||||||
|
</param>
|
||||||
|
|
||||||
|
</params>
|
||||||
|
</fn>
|
||||||
|
|
||||||
|
</virtualFns>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
</type>
|
||||||
|
|
||||||
|
</tm2>
|
||||||
|
|
||||||
444
aqhome/data/datafile_direct.c
Normal file
444
aqhome/data/datafile_direct.c
Normal file
@@ -0,0 +1,444 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* This file is part of the project Gwenhywfar.
|
||||||
|
* Gwenhywfar (c) by 2023 Martin Preuss, all rights reserved.
|
||||||
|
*
|
||||||
|
* The license for this file can be found in the file COPYING which you
|
||||||
|
* should have received along with this file.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifdef HAVE_CONFIG_H
|
||||||
|
# include <config.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include "./datafile_direct_p.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/debug.h>
|
||||||
|
#include <gwenhywfar/syncio_file.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
|
||||||
|
GWEN_INHERIT(AQH_DATAFILE, AQH_DATAFILE_DIRECT);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* forward declarations
|
||||||
|
* ------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
static void _cbFreeData(void *bp, void *p);
|
||||||
|
|
||||||
|
static int _cbCreate(AQH_DATAFILE *df);
|
||||||
|
static int _cbOpen(AQH_DATAFILE *df);
|
||||||
|
static int _cbClose(AQH_DATAFILE *df);
|
||||||
|
|
||||||
|
static uint64_t _cbGetNumberOfEntries(AQH_DATAFILE *df);
|
||||||
|
|
||||||
|
static int _cbReadRecord(AQH_DATAFILE *df, uint64_t idx, uint64_t *pTimestamp, double *pValue);
|
||||||
|
static int _cbAppendRecord(AQH_DATAFILE *df, uint64_t timestamp, double value);
|
||||||
|
|
||||||
|
static int _readRecord(GWEN_SYNCIO *sio, uint64_t idx, uint64_t *pTimestamp, double *pValue);
|
||||||
|
static int _writeRecord(GWEN_SYNCIO *sio, uint64_t filePos, uint64_t timestamp, double value);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
/* ------------------------------------------------------------------------------------------------
|
||||||
|
* implementations
|
||||||
|
* ------------------------------------------------------------------------------------------------
|
||||||
|
*/
|
||||||
|
|
||||||
|
AQH_DATAFILE *AQH_DataFileDirect_new(const char *fileName, uint64_t valueId)
|
||||||
|
{
|
||||||
|
AQH_DATAFILE *df;
|
||||||
|
AQH_DATAFILE_DIRECT *xdf;
|
||||||
|
|
||||||
|
df=AQH_DataFile_new();
|
||||||
|
AQH_DataFile_SetValueId(df, valueId);
|
||||||
|
|
||||||
|
GWEN_NEW_OBJECT(AQH_DATAFILE_DIRECT, xdf);
|
||||||
|
xdf->fileName=fileName?strdup(fileName):NULL;
|
||||||
|
GWEN_INHERIT_SETDATA(AQH_DATAFILE, AQH_DATAFILE_DIRECT, df, xdf, _cbFreeData);
|
||||||
|
|
||||||
|
AQH_DataFile_SetCreateFn(df, _cbCreate);
|
||||||
|
AQH_DataFile_SetOpenFn(df, _cbOpen);
|
||||||
|
AQH_DataFile_SetCloseFn(df, _cbClose);
|
||||||
|
AQH_DataFile_SetGetNumberOfEntriesFn(df, _cbGetNumberOfEntries);
|
||||||
|
AQH_DataFile_SetReadRecordFn(df, _cbReadRecord);
|
||||||
|
AQH_DataFile_SetAppendRecordFn(df, _cbAppendRecord);
|
||||||
|
|
||||||
|
return df;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void _cbFreeData(void *bp, void *p)
|
||||||
|
{
|
||||||
|
AQH_DATAFILE_DIRECT *xdf;
|
||||||
|
|
||||||
|
xdf=(AQH_DATAFILE_DIRECT*)p;
|
||||||
|
GWEN_SyncIo_free(xdf->sio);
|
||||||
|
free(xdf->fileName);
|
||||||
|
GWEN_FREE_OBJECT(xdf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
const char *_cbGetFileName(const AQH_DATAFILE *df)
|
||||||
|
{
|
||||||
|
AQH_DATAFILE_DIRECT *xdf;
|
||||||
|
|
||||||
|
xdf=GWEN_INHERIT_GETDATA(AQH_DATAFILE, AQH_DATAFILE_DIRECT, df);
|
||||||
|
return xdf?xdf->fileName:NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
uint64_t _cbGetNumberOfEntries(AQH_DATAFILE *df)
|
||||||
|
{
|
||||||
|
AQH_DATAFILE_DIRECT *xdf;
|
||||||
|
|
||||||
|
xdf=GWEN_INHERIT_GETDATA(AQH_DATAFILE, AQH_DATAFILE_DIRECT, df);
|
||||||
|
return xdf?xdf->numberOfEntries:0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _cbCreate(AQH_DATAFILE *df)
|
||||||
|
{
|
||||||
|
if (df) {
|
||||||
|
AQH_DATAFILE_DIRECT *xdf;
|
||||||
|
|
||||||
|
xdf=GWEN_INHERIT_GETDATA(AQH_DATAFILE, AQH_DATAFILE_DIRECT, df);
|
||||||
|
if (xdf) {
|
||||||
|
GWEN_SYNCIO *sio;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (xdf->sio) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "File already open");
|
||||||
|
return GWEN_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
sio=GWEN_SyncIo_File_new(xdf->fileName, GWEN_SyncIo_File_CreationMode_CreateNew);
|
||||||
|
GWEN_SyncIo_SetFlags(sio,
|
||||||
|
GWEN_SYNCIO_FILE_FLAGS_WRITE | GWEN_SYNCIO_FILE_FLAGS_READ |
|
||||||
|
GWEN_SYNCIO_FILE_FLAGS_UREAD | GWEN_SYNCIO_FILE_FLAGS_UWRITE);
|
||||||
|
rv=GWEN_SyncIo_Connect(sio);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Error creating file \"%s\" (%d)", xdf->fileName, rv);
|
||||||
|
GWEN_SyncIo_free(sio);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
rv=_writeRecord(sio, 0, 0, 0.0);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_DEBUG(AQH_LOGDOMAIN, "Error adding first record to file \"%s\" (%d)", xdf->fileName, rv);
|
||||||
|
GWEN_SyncIo_free(sio);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
xdf->sio=sio;
|
||||||
|
xdf->numberOfEntries=1; /* we just added the 0-record */
|
||||||
|
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "File \"%s\" created.", xdf->fileName);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Not of type AQH_DATAFILE_DIRECT");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Nullpointer");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _cbOpen(AQH_DATAFILE *df)
|
||||||
|
{
|
||||||
|
if (df) {
|
||||||
|
AQH_DATAFILE_DIRECT *xdf;
|
||||||
|
|
||||||
|
xdf=GWEN_INHERIT_GETDATA(AQH_DATAFILE, AQH_DATAFILE_DIRECT, df);
|
||||||
|
if (xdf) {
|
||||||
|
GWEN_SYNCIO *sio;
|
||||||
|
int rv;
|
||||||
|
int64_t len;
|
||||||
|
|
||||||
|
if (xdf->sio) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "File already open");
|
||||||
|
return GWEN_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
sio=GWEN_SyncIo_File_new(xdf->fileName, GWEN_SyncIo_File_CreationMode_OpenExisting);
|
||||||
|
GWEN_SyncIo_SetFlags(sio, GWEN_SYNCIO_FILE_FLAGS_WRITE | GWEN_SYNCIO_FILE_FLAGS_READ);
|
||||||
|
rv=GWEN_SyncIo_Connect(sio);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Error opening file \"%s\" (%d)", xdf->fileName, rv);
|
||||||
|
GWEN_SyncIo_free(sio);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
len=GWEN_SyncIo_File_Seek(sio, 0, GWEN_SyncIo_File_Whence_End);
|
||||||
|
if (len<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Error seeking to end of file \"%s\" (%d)", xdf->fileName, rv);
|
||||||
|
GWEN_SyncIo_free(sio);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
if (len % AQH_DATAFILE_RECORDSIZE) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Invalid file size of file \"%s\" (not a multiple of current record size)", xdf->fileName);
|
||||||
|
GWEN_SyncIo_Disconnect(sio);
|
||||||
|
GWEN_SyncIo_free(sio);
|
||||||
|
unlink(xdf->fileName);
|
||||||
|
return GWEN_ERROR_BAD_DATA;
|
||||||
|
}
|
||||||
|
xdf->numberOfEntries=len/AQH_DATAFILE_RECORDSIZE;
|
||||||
|
|
||||||
|
len=GWEN_SyncIo_File_Seek(sio, 0, GWEN_SyncIo_File_Whence_Set);
|
||||||
|
if (len<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Error seeking to begin of file \"%s\" (%d)", xdf->fileName, rv);
|
||||||
|
GWEN_SyncIo_free(sio);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
xdf->sio=sio;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Not of type AQH_DATAFILE_DIRECT");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Nullpointer");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _cbClose(AQH_DATAFILE *df)
|
||||||
|
{
|
||||||
|
if (df) {
|
||||||
|
AQH_DATAFILE_DIRECT *xdf;
|
||||||
|
|
||||||
|
xdf=GWEN_INHERIT_GETDATA(AQH_DATAFILE, AQH_DATAFILE_DIRECT, df);
|
||||||
|
if (xdf) {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (xdf->sio==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "File not open");
|
||||||
|
return GWEN_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv=GWEN_SyncIo_Disconnect(xdf->sio);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Error closing file \"%s\" (%d)", xdf->fileName, rv);
|
||||||
|
GWEN_SyncIo_free(xdf->sio);
|
||||||
|
xdf->sio=NULL;
|
||||||
|
xdf->numberOfEntries=0;
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
GWEN_SyncIo_free(xdf->sio);
|
||||||
|
xdf->sio=NULL;
|
||||||
|
xdf->numberOfEntries=0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Not of type AQH_DATAFILE_DIRECT");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Nullpointer");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _cbReadRecord(AQH_DATAFILE *df, uint64_t idx, uint64_t *pTimestamp, double *pValue)
|
||||||
|
{
|
||||||
|
if (df) {
|
||||||
|
AQH_DATAFILE_DIRECT *xdf;
|
||||||
|
|
||||||
|
xdf=GWEN_INHERIT_GETDATA(AQH_DATAFILE, AQH_DATAFILE_DIRECT, df);
|
||||||
|
if (xdf) {
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
if (xdf->sio==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "File not open");
|
||||||
|
return GWEN_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv=_readRecord(xdf->sio, idx, pTimestamp, pValue);;
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Error reading from file \"%s\" (%d)", xdf->fileName, rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Not of type AQH_DATAFILE_DIRECT");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Nullpointer");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _cbAppendRecord(AQH_DATAFILE *df, uint64_t timestamp, double value)
|
||||||
|
{
|
||||||
|
if (df) {
|
||||||
|
AQH_DATAFILE_DIRECT *xdf;
|
||||||
|
|
||||||
|
xdf=GWEN_INHERIT_GETDATA(AQH_DATAFILE, AQH_DATAFILE_DIRECT, df);
|
||||||
|
if (xdf) {
|
||||||
|
int rv;
|
||||||
|
uint64_t filePos;
|
||||||
|
|
||||||
|
if (xdf->sio==NULL) {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "File not open");
|
||||||
|
return GWEN_ERROR_INVALID;
|
||||||
|
}
|
||||||
|
|
||||||
|
filePos=(xdf->numberOfEntries)*AQH_DATAFILE_RECORDSIZE;
|
||||||
|
rv=_writeRecord(xdf->sio, filePos, timestamp, value);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Error writing to file \"%s\" (%d)", xdf->fileName, rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
xdf->numberOfEntries++;
|
||||||
|
DBG_DEBUG(AQH_LOGDOMAIN, "File \"%s\" has now %lu entries", xdf->fileName, (unsigned long int) (xdf->numberOfEntries));
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Not of type AQH_DATAFILE_DIRECT");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
DBG_ERROR(AQH_LOGDOMAIN, "Nullpointer");
|
||||||
|
return GWEN_ERROR_GENERIC;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _readRecord(GWEN_SYNCIO *sio, uint64_t idx, uint64_t *pTimestamp, double *pValue)
|
||||||
|
{
|
||||||
|
uint8_t record[AQH_DATAFILE_RECORDSIZE];
|
||||||
|
union {double f; uint64_t i;} u;
|
||||||
|
uint64_t filePos;
|
||||||
|
int64_t retPos;
|
||||||
|
const uint8_t *ptr;
|
||||||
|
uint64_t v;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
filePos=idx*AQH_DATAFILE_RECORDSIZE;
|
||||||
|
retPos=GWEN_SyncIo_File_Seek(sio, filePos, GWEN_SyncIo_File_Whence_Set);
|
||||||
|
if (retPos<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Error seeking to pos %lu (%d)", (unsigned long int) filePos, (int) retPos);
|
||||||
|
return (int) retPos;
|
||||||
|
}
|
||||||
|
|
||||||
|
rv=GWEN_SyncIo_ReadForced(sio, record, AQH_DATAFILE_RECORDSIZE);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Error reading at pos %lu (%d)", (unsigned long int) filePos, rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
|
||||||
|
ptr=record+AQH_DATAFILE_OFFSET_TIMESTAMP;
|
||||||
|
v=0;
|
||||||
|
v|=(uint64_t)(*(ptr++));
|
||||||
|
v|=(uint64_t)(*(ptr++))<<8;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<16;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<24;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<32;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<40;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<48;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<56;
|
||||||
|
*pTimestamp=v;
|
||||||
|
|
||||||
|
ptr=record+AQH_DATAFILE_OFFSET_VALUE;
|
||||||
|
v=0;
|
||||||
|
v|=(uint64_t)(*(ptr++));
|
||||||
|
v|=(uint64_t)(*(ptr++))<<8;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<16;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<24;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<32;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<40;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<48;
|
||||||
|
v|=(uint64_t)(*(ptr++))<<56;
|
||||||
|
u.i=v;
|
||||||
|
*pValue=u.f;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
int _writeRecord(GWEN_SYNCIO *sio, uint64_t filePos, uint64_t timestamp, double value)
|
||||||
|
{
|
||||||
|
uint8_t record[AQH_DATAFILE_RECORDSIZE];
|
||||||
|
union {double f; uint64_t i;} u;
|
||||||
|
uint8_t *ptr;
|
||||||
|
int64_t retPos;
|
||||||
|
uint64_t v;
|
||||||
|
int rv;
|
||||||
|
|
||||||
|
ptr=record+AQH_DATAFILE_OFFSET_TIMESTAMP;
|
||||||
|
v=timestamp;
|
||||||
|
*(ptr++)=(v) & 0xff;
|
||||||
|
*(ptr++)=(v>>8) & 0xff;
|
||||||
|
*(ptr++)=(v>>16) & 0xff;
|
||||||
|
*(ptr++)=(v>>24) & 0xff;
|
||||||
|
*(ptr++)=(v>>32) & 0xff;
|
||||||
|
*(ptr++)=(v>>40) & 0xff;
|
||||||
|
*(ptr++)=(v>>48) & 0xff;
|
||||||
|
*(ptr++)=(v>>56) & 0xff;
|
||||||
|
|
||||||
|
u.f=value;
|
||||||
|
v=u.i;
|
||||||
|
ptr=record+AQH_DATAFILE_OFFSET_VALUE;
|
||||||
|
*(ptr++)=(v) & 0xff;
|
||||||
|
*(ptr++)=(v>>8) & 0xff;
|
||||||
|
*(ptr++)=(v>>16) & 0xff;
|
||||||
|
*(ptr++)=(v>>24) & 0xff;
|
||||||
|
*(ptr++)=(v>>32) & 0xff;
|
||||||
|
*(ptr++)=(v>>40) & 0xff;
|
||||||
|
*(ptr++)=(v>>48) & 0xff;
|
||||||
|
*(ptr++)=(v>>56) & 0xff;
|
||||||
|
|
||||||
|
retPos=GWEN_SyncIo_File_Seek(sio, filePos, GWEN_SyncIo_File_Whence_Set);
|
||||||
|
if (retPos<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Error seeking to pos %lu (%d)", (unsigned long int) filePos, (int) retPos);
|
||||||
|
return (int) retPos;
|
||||||
|
}
|
||||||
|
rv=GWEN_SyncIo_WriteForced(sio, record, AQH_DATAFILE_RECORDSIZE);
|
||||||
|
if (rv<0) {
|
||||||
|
DBG_INFO(AQH_LOGDOMAIN, "Error writing to file (%d)", rv);
|
||||||
|
return rv;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
26
aqhome/data/datafile_direct.h
Normal file
26
aqhome/data/datafile_direct.h
Normal file
@@ -0,0 +1,26 @@
|
|||||||
|
/****************************************************************************
|
||||||
|
* This file is part of the project Gwenhywfar.
|
||||||
|
* Gwenhywfar (c) by 2023 Martin Preuss, all rights reserved.
|
||||||
|
*
|
||||||
|
* The license for this file can be found in the file COPYING which you
|
||||||
|
* should have received along with this file.
|
||||||
|
****************************************************************************/
|
||||||
|
|
||||||
|
#ifndef AQH_DATAFILE_H
|
||||||
|
#define AQH_DATAFILE_H
|
||||||
|
|
||||||
|
|
||||||
|
#include "aqhome/data/storage.h"
|
||||||
|
#include "aqhome/data/datafile.h"
|
||||||
|
|
||||||
|
#include <gwenhywfar/list.h>
|
||||||
|
|
||||||
|
|
||||||
|
AQHOME_API AQH_DATAFILE *AQH_DataFileDirect_new(const char *fileName, uint64_t valueId);
|
||||||
|
|
||||||
|
AQHOME_API const char *AQH_DataFileDirect_GetFileName(const AQH_DATAFILE *df);
|
||||||
|
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
@@ -6,11 +6,11 @@
|
|||||||
* should have received along with this file.
|
* should have received along with this file.
|
||||||
****************************************************************************/
|
****************************************************************************/
|
||||||
|
|
||||||
#ifndef AQH_DATAFILE_P_H
|
#ifndef AQH_DATAFILE_DIRECT_P_H
|
||||||
#define AQH_DATAFILE_P_H
|
#define AQH_DATAFILE_DIRECT_P_H
|
||||||
|
|
||||||
|
|
||||||
#include "./datafile.h"
|
#include "./datafile_direct.h"
|
||||||
|
|
||||||
#include <gwenhywfar/syncio.h>
|
#include <gwenhywfar/syncio.h>
|
||||||
|
|
||||||
@@ -20,14 +20,11 @@
|
|||||||
#define AQH_DATAFILE_OFFSET_VALUE 8
|
#define AQH_DATAFILE_OFFSET_VALUE 8
|
||||||
|
|
||||||
|
|
||||||
struct AQH_DATAFILE {
|
typedef struct AQH_DATAFILE_DIRECT AQH_DATAFILE_DIRECT;
|
||||||
GWEN_LIST_ELEMENT(AQH_DATAFILE);
|
struct AQH_DATAFILE_DIRECT {
|
||||||
|
|
||||||
char *fileName;
|
char *fileName;
|
||||||
uint64_t valueId;
|
|
||||||
GWEN_SYNCIO *sio;
|
GWEN_SYNCIO *sio;
|
||||||
uint64_t numberOfEntries;
|
uint64_t numberOfEntries;
|
||||||
uint32_t runtimeFlags;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@@ -13,6 +13,7 @@
|
|||||||
#include "aqhome/data/storage_p.h"
|
#include "aqhome/data/storage_p.h"
|
||||||
#include "aqhome/data/storage_readxml.h"
|
#include "aqhome/data/storage_readxml.h"
|
||||||
#include "aqhome/data/storage_writexml.h"
|
#include "aqhome/data/storage_writexml.h"
|
||||||
|
#include "aqhome/data/datafile_direct.h"
|
||||||
|
|
||||||
#include <gwenhywfar/debug.h>
|
#include <gwenhywfar/debug.h>
|
||||||
#include <gwenhywfar/xml.h>
|
#include <gwenhywfar/xml.h>
|
||||||
@@ -353,7 +354,7 @@ int AQH_Storage_Fini(AQH_STORAGE *sto)
|
|||||||
AQH_DataFile_List_Del(df);
|
AQH_DataFile_List_Del(df);
|
||||||
rv=AQH_DataFile_Close(df);
|
rv=AQH_DataFile_Close(df);
|
||||||
if (rv<0) {
|
if (rv<0) {
|
||||||
DBG_INFO(AQH_LOGDOMAIN, "Error closing file \"%s\"", AQH_DataFile_GetFileName(df));
|
DBG_INFO(AQH_LOGDOMAIN, "Error closing file \"%lu\"", AQH_DataFile_GetValueId(df));
|
||||||
errors++;
|
errors++;
|
||||||
}
|
}
|
||||||
AQH_DataFile_free(df);
|
AQH_DataFile_free(df);
|
||||||
@@ -625,7 +626,7 @@ AQH_DATAFILE *_openOrCreateDataFileByValueId(AQH_STORAGE *sto, uint64_t valueId)
|
|||||||
int rv;
|
int rv;
|
||||||
|
|
||||||
nameBuf=_getDataFilePathForValueId(sto, valueId);
|
nameBuf=_getDataFilePathForValueId(sto, valueId);
|
||||||
df=AQH_DataFile_new(GWEN_Buffer_GetStart(nameBuf), valueId);
|
df=AQH_DataFileDirect_new(GWEN_Buffer_GetStart(nameBuf), valueId);
|
||||||
|
|
||||||
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf),
|
rv=GWEN_Directory_GetPath(GWEN_Buffer_GetStart(nameBuf),
|
||||||
GWEN_PATH_FLAGS_CHECKROOT |
|
GWEN_PATH_FLAGS_CHECKROOT |
|
||||||
|
|||||||
Reference in New Issue
Block a user