Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Store layer metadata #401

Merged
merged 67 commits into from
Sep 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
1a26063
Converting projection list to json
maartenplieger Sep 2, 2024
c27cf13
Updated with remote branch
maartenplieger Sep 2, 2024
9152b17
Store and retrieve is working for layer boundingboxes
maartenplieger Sep 3, 2024
754708a
Merge branch 'master' of github.com:KNMI/adaguc-server into store-lay…
maartenplieger Sep 3, 2024
be6d15b
Renamed files
maartenplieger Sep 3, 2024
caa8ab7
Refactored CXMLGen
maartenplieger Sep 4, 2024
03faae3
Merge branch 'master' of github.com:KNMI/adaguc-server into store-lay…
maartenplieger Sep 4, 2024
be61a63
Reduced loggings
maartenplieger Sep 4, 2024
8cc797e
Refactored CXMLGen
maartenplieger Sep 5, 2024
cffe53d
Commit before fixing tests
maartenplieger Sep 5, 2024
a1d8ec3
Tests without store do work
maartenplieger Sep 5, 2024
79d71d5
Tests succeed
maartenplieger Sep 5, 2024
da373cc
Stylelist is ordered as before
maartenplieger Sep 6, 2024
38319b7
enablemetadatacache can be enabled/disabled via the settings
maartenplieger Sep 6, 2024
8d2afae
Metadatatable enabled by default
maartenplieger Sep 6, 2024
91e2483
Update on conflict is working based on the defaultValue of the time d…
maartenplieger Sep 6, 2024
71b50cb
Resolved comments
maartenplieger Sep 9, 2024
1fdf9b6
Fixed describecoverage
maartenplieger Sep 9, 2024
c719e01
Fixed tests
maartenplieger Sep 9, 2024
eb6b6d4
Resolved comments
maartenplieger Sep 9, 2024
5026730
added call to obtain metadata
maartenplieger Sep 9, 2024
526bbe0
Resolved comments
maartenplieger Sep 9, 2024
f51e22a
Resolved comments
maartenplieger Sep 10, 2024
7a27a30
Merge branch 'store-layer-metadata' of github.com:KNMI/adaguc-server …
maartenplieger Sep 10, 2024
f3e3b3b
Moved json generation to another file
maartenplieger Sep 10, 2024
cf262fd
Resolved comments
maartenplieger Sep 10, 2024
2e893d4
Merge branch 'store-layer-metadata' of github.com:KNMI/adaguc-server …
maartenplieger Sep 10, 2024
e5fff45
Resolved comments
maartenplieger Sep 10, 2024
086429d
Merge branch 'store-layer-metadata' of github.com:KNMI/adaguc-server …
maartenplieger Sep 10, 2024
a19f085
Added getmetadata call
maartenplieger Sep 11, 2024
3d0353d
Resolved comments
maartenplieger Sep 11, 2024
fecec15
Merged from master
maartenplieger Sep 11, 2024
a478bfd
Fixed nullptr issue
maartenplieger Sep 11, 2024
22d50c0
Added test
maartenplieger Sep 11, 2024
d7cced3
Resolved comments
maartenplieger Sep 11, 2024
39b7c69
Merge branch 'store-layer-metadata' of github.com:KNMI/adaguc-server …
maartenplieger Sep 11, 2024
bf2d1b9
Resolved comments
maartenplieger Sep 11, 2024
00d3cfa
merge from store-layer-metadata
maartenplieger Sep 11, 2024
9b1f648
Removed pointers
maartenplieger Sep 12, 2024
7ef7f50
Resolved comments
maartenplieger Sep 12, 2024
895f0cb
Resolved comments
maartenplieger Sep 12, 2024
84e93e6
Fix compare and struct initialisation.
lukas-phaf Sep 12, 2024
1764e17
Merged from store-layer-metadata
maartenplieger Sep 12, 2024
79e3b64
Stylelist and projected_extents are now returned in metadata call
maartenplieger Sep 12, 2024
85438af
Added exception logic in metadata call
maartenplieger Sep 12, 2024
6a82023
Fixed bbox listings in CXMLGen
maartenplieger Sep 12, 2024
23f53b6
Updated tests
maartenplieger Sep 12, 2024
11fd40d
Taking changes from get-layer-metadata
maartenplieger Sep 13, 2024
90c3e5e
up to date with store-layer metadata
maartenplieger Sep 13, 2024
33f5e1c
Fixed tests
maartenplieger Sep 13, 2024
52b2fa9
Using TIMESTAMPTZ in layermetadatatable
maartenplieger Sep 13, 2024
a48c9d2
Added --updatelayermetadata option to update layermetadata
maartenplieger Sep 13, 2024
552e28c
Using already existing data base filename loader
maartenplieger Sep 13, 2024
47186df
--updatelayermetadata does now clean as well
maartenplieger Sep 13, 2024
36841ec
Updated populateMetadataLayerStruct
maartenplieger Sep 13, 2024
552ef61
Merge branch 'get-layer-metadata' of github.com:KNMI/adaguc-server in…
maartenplieger Sep 13, 2024
ea4beec
Updated with store-layer-metadata
maartenplieger Sep 13, 2024
61a5b8a
Fixed tests
maartenplieger Sep 13, 2024
41e7dd5
Get rid of default constructor for LayerMetadataProjection.
lukas-phaf Sep 13, 2024
fdad104
Added advisory lock to lock layermetadatatable
maartenplieger Sep 23, 2024
38fce6e
Rewrite of updatelayer metadata from two nested maps into two sets
maartenplieger Sep 23, 2024
e9aa622
Merge branch 'store-layer-metadata' of github.com:KNMI/adaguc-server …
maartenplieger Sep 24, 2024
560c888
Added extra metadata entries
maartenplieger Sep 24, 2024
1518d19
Solved bug where brotli caused huge delays when storing cached data i…
maartenplieger Sep 24, 2024
ba09d04
Merge pull request #406 from KNMI/get-layer-metadata
ernstdevreede Sep 24, 2024
2ec2e62
Reverted brotli change
maartenplieger Sep 25, 2024
3da962d
Updated with master
maartenplieger Sep 25, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 9 additions & 9 deletions CCDFDataModel/CCDFVariable.h
Original file line number Diff line number Diff line change
Expand Up @@ -292,20 +292,20 @@ namespace CDF {
size_t getSize() { return currentSize; }

Attribute *getAttribute(const char *name) const {
Attribute *a = getAttributeNE(name);
if (a == nullptr) {
throw(CDF_E_ATTNOTFOUND);
}
return a;
}

Attribute *getAttributeNE(const char *name) const {
lukas-phaf marked this conversation as resolved.
Show resolved Hide resolved
for (size_t j = 0; j < attributes.size(); j++) {
if (attributes[j]->name.equals(name)) {
return attributes[j];
}
}
throw(CDF_E_ATTNOTFOUND);
return NULL;
}
Attribute *getAttributeNE(const char *name) const {
try {
return getAttribute(name);
} catch (int e) {
return NULL;
}
return nullptr;
}

/**
Expand Down
2 changes: 1 addition & 1 deletion CCDFDataModel/CTime.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -878,7 +878,7 @@ CT::string CTime::currentDateTime() {
strftime(buffer, 80, "%Y-%m-%dT%H:%M:%S", gmtime(&curTime.tv_sec));

char currentTime[100] = "";
snprintf(currentTime, 99, "%s:%03dZ", buffer, milli);
snprintf(currentTime, 99, "%s.%03dZ", buffer, milli);

return currentTime;
}
Expand Down
4 changes: 2 additions & 2 deletions Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ USER root
LABEL maintainer="[email protected]"

# Version should be same as in Definitions.h
LABEL version="2.27.0"
LABEL version="2.28.0"

# Try to update image packages
RUN apt-get -q -y update \
Expand Down Expand Up @@ -88,7 +88,7 @@ COPY python /adaguc/adaguc-server-master/python
# To run the tests against a postgres db, see docs/test_postgesql.md
FROM base AS test

ENV TEST_IN_CONTAINER 1
ENV TEST_IN_CONTAINER=1

COPY requirements-dev.txt /adaguc/adaguc-server-master/requirements-dev.txt
RUN pip install --no-cache-dir -r requirements-dev.txt
Expand Down
5 changes: 5 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
**Version 2.28.0 2024-09-11**
- Metadata for layer items like variables, projections, dimensions and styles are now stored in a database table called `layermetadata`. This can be disabled via the `enablemetadatacache` property in [Settings](doc/configuration/Settings.md).



**Version 2.27.0 2024-09-02**
- PostgreSQL query from `getFilesAndIndicesForDimensions` has been rewritten, which fixes https://github.com/KNMI/adaguc-server/issues/341.
- Optimized existing PostgreSQL queries and reduced number of PostgreSQL queries in general. This results in better performance, the benchmark tool runs 9% faster.
Expand Down
66 changes: 41 additions & 25 deletions adagucserverEC/CAutoConfigure.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -463,31 +463,13 @@ int CAutoConfigure::autoConfigureStyles(CDataSource *dataSource) {
return 0;
}

int CAutoConfigure::justLoadAFileHeader(CDataSource *dataSource) {
int CAutoConfigure::getFileNameForDataSource(CDataSource *dataSource, std::string &fileName) {

if (dataSource == NULL) {
CDBError("datasource == NULL");
return 1;
}
if (dataSource->cfgLayer == NULL) {
CDBError("datasource->cfgLayer == NULL");
return 1;
}
if (dataSource->getNumDataObjects() == 0) {
CDBError("dataSource->getNumDataObjects()==0");
return 1;
}
if (dataSource->getDataObject(0)->cdfVariable != NULL) {
#ifdef CAUTOCONFIGURE_DEBUG
CDBDebug("already loaded: dataSource->getDataObject(0)->cdfVariable!=NULL");
#endif
return 0;
CT::string foundFileName = dataSource->getFileName();
if (foundFileName.empty()) {
/* Use the file specified as header file */
foundFileName = dataSource->headerFileName.c_str();
}

CT::string foundFileName;

/* Use the file specified as header file */
foundFileName = dataSource->headerFileName.c_str();
if (foundFileName.empty()) {

/* Try to get a file from DB */
Expand All @@ -498,7 +480,12 @@ int CAutoConfigure::justLoadAFileHeader(CDataSource *dataSource) {
if (dataSource->requiredDims.size() == 0) {
removeRequiredDims = true;
if (dataSource->cfgLayer->Dimension.size() > 0) {
CRequest::fillDimValuesForDataSource(dataSource, dataSource->srvParams);
try {
CRequest::fillDimValuesForDataSource(dataSource, dataSource->srvParams);
} catch (ServiceExceptionCode e) {
CDBDebug("Unable to fillDimValuesForDataSource");
return 1;
}
} else {
CDBDebug("Required dims is still zero, add none now");
COGCDims *ogcDim = new COGCDims();
Expand All @@ -509,7 +496,7 @@ int CAutoConfigure::justLoadAFileHeader(CDataSource *dataSource) {
ogcDim->netCDFDimName.copy("none");
}
}
CDBStore::Store *store = CDBFactory::getDBAdapter(dataSource->srvParams->cfg)->getFilesAndIndicesForDimensions(dataSource, 1000);
CDBStore::Store *store = CDBFactory::getDBAdapter(dataSource->srvParams->cfg)->getFilesAndIndicesForDimensions(dataSource, 1);
if (store != NULL && store->getSize() > 0) {
CT::string fileNamestr = store->getRecord(0)->get(0)->c_str();
// CDBDebug("fileName from DB: %s", fileNamestr.c_str());
Expand All @@ -531,7 +518,36 @@ int CAutoConfigure::justLoadAFileHeader(CDataSource *dataSource) {
return 1;
}
}
fileName = foundFileName.c_str();
return 0;
}

int CAutoConfigure::justLoadAFileHeader(CDataSource *dataSource) {
if (dataSource == NULL) {
CDBError("datasource == NULL");
return 1;
}
if (dataSource->cfgLayer == NULL) {
CDBError("datasource->cfgLayer == NULL");
return 1;
}
if (dataSource->getNumDataObjects() == 0) {
CDBError("dataSource->getNumDataObjects()==0");
return 1;
}
if (dataSource->getDataObject(0)->cdfVariable != NULL) {
#ifdef CAUTOCONFIGURE_DEBUG
CDBDebug("already loaded: dataSource->getDataObject(0)->cdfVariable!=NULL");
#endif
return 0;
}

std::string foundFileName;

if (getFileNameForDataSource(dataSource, foundFileName) != 0) {
CDBDebug("Unable to getFileNameForDataSource");
return 1;
}
/* Open a file */
try {
// CDBDebug("Loading header [%s]", foundFileName.c_str());
Expand Down
8 changes: 8 additions & 0 deletions adagucserverEC/CAutoConfigure.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,5 +56,13 @@ class CAutoConfigure {
public:
static int autoConfigureDimensions(CDataSource *dataSource);
static int autoConfigureStyles(CDataSource *dataSource);

/**
* Find the default filename for a datasource from the database
* @param dataSource
* @param fileName - The filename to return
* @returns Zero on success.
*/
static int getFileNameForDataSource(CDataSource *dataSource, std::string &fileName);
};
#endif
9 changes: 8 additions & 1 deletion adagucserverEC/CDBAdapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
class CDBAdapter {
public:
CDBAdapter() {}
virtual ~CDBAdapter(){};
virtual ~CDBAdapter() {};

class GeoOptions {
public:
Expand Down Expand Up @@ -96,6 +96,13 @@ class CDBAdapter {

/** First use setFile<type> as many times as you whish, second use addFilesToDataBase to make it final*/
virtual int addFilesToDataBase() = 0;

virtual int storeLayerMetadata(const char *datasetName, const char *layerName, const char *metadataKey, const char *metadatablob) = 0;
virtual CDBStore::Store *getLayerMetadataStore(const char *datasetName) = 0;
virtual int dropLayerFromLayerMetadataStore(const char *datasetName, const char *layerName) = 0;

virtual bool tryAdvisoryLock(size_t key) = 0;
virtual bool advisoryUnLock(size_t key) = 0;
};

#endif
145 changes: 143 additions & 2 deletions adagucserverEC/CDBAdapterPostgreSQL.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ CDBAdapterPostgreSQL::~CDBAdapterPostgreSQL() {
#ifdef CDBAdapterPostgreSQL_DEBUG
CDBDebug("~CDBAdapterPostgreSQL()");
#endif
if (layerMetaDataStore != nullptr) {
delete layerMetaDataStore;
layerMetaDataStore = nullptr;
}
if (dataBaseConnection != NULL) {
dataBaseConnection->close2();
}
Expand Down Expand Up @@ -423,7 +427,7 @@ CDBStore::Store *CDBAdapterPostgreSQL::getFilesAndIndicesForDimensions(CDataSour
CT::string whereStatement;
std::vector<CT::string> requestedDimVals = requestedDimMap[m.first];

for (int i = 0; i < requestedDimVals.size(); ++i) {
for (size_t i = 0; i < requestedDimVals.size(); ++i) {
if (requestedDimVals[i].equals("*")) continue;

if (i != 0) {
Expand Down Expand Up @@ -620,6 +624,7 @@ void CDBAdapterPostgreSQL::addToLookupTable(const char *path, const char *filter
CT::string CDBAdapterPostgreSQL::generateRandomTableName() {
CT::string tableName;
tableName.print("t%s_%s", CTime::currentDateTime().c_str(), CServerParams::randomString(20).c_str());
tableName.replaceSelf(".", "");
tableName.replaceSelf(":", "");
tableName.replaceSelf("-", "");
tableName.replaceSelf("Z", "");
Expand Down Expand Up @@ -717,7 +722,7 @@ std::map<CT::string, DimInfo> CDBAdapterPostgreSQL::getTableNamesForPathFilterAn
}

// Found all tablenames for requested dimensions in lookup table
int found = tableDimStore->size();
size_t found = tableDimStore->size();
delete tableDimStore;
if (found == mapping.size()) {
#ifdef MEASURETIME
Expand Down Expand Up @@ -1080,3 +1085,139 @@ int CDBAdapterPostgreSQL::addFilesToDataBase() {
#endif
return 0;
}

int CDBAdapterPostgreSQL::storeLayerMetadata(const char *datasetName, const char *layerName, const char *metadataKey, const char *metadataBlob) {
lukas-phaf marked this conversation as resolved.
Show resolved Hide resolved
#ifdef MEASURETIME
StopWatch_Stop(">CDBAdapterPostgreSQL::storeLayerMetadata");
#endif
CPGSQLDB *dataBaseConnection = getDataBaseConnection();
if (dataBaseConnection == NULL) {
return -1;
belentorrente marked this conversation as resolved.
Show resolved Hide resolved
}

CT::string tableColumns("datasetname varchar (511), layername varchar (511), metadatakey varchar (255), updatetime TIMESTAMPTZ, blob JSONB, PRIMARY KEY (datasetname, layername, metadatakey)");

int status = dataBaseConnection->checkTable("layermetadata", tableColumns.c_str());
if (status == 1) {
CDBError("\nFAIL: Table layermetadata could not be created: %s", tableColumns.c_str());
throw(__LINE__);
}

CT::string updateTime = CTime::currentDateTime().c_str();
CT::string query;
query.print("INSERT INTO layermetadata (datasetname, layername, metadatakey, updatetime, blob) "
"VALUES (E'%s',E'%s', E'%s', E'%s', E'%s') "
"ON CONFLICT (datasetname, layername, metadatakey) "
"DO UPDATE SET blob = excluded.blob, updatetime = excluded.updatetime;",
datasetName, layerName, metadataKey, updateTime.c_str(), metadataBlob);

status = dataBaseConnection->query(query.c_str());
if (status != 0) {
CDBError("Unable to insert records: \"%s\"", query.c_str());
throw(__LINE__);
}
#ifdef MEASURETIME
StopWatch_Stop("<CDBAdapterPostgreSQL::storeLayerMetadata");
#endif
return 0;
}

CDBStore::Store *CDBAdapterPostgreSQL::getLayerMetadataStore(const char *datasetName) {
#ifdef MEASURETIME
StopWatch_Stop(">CDBAdapterPostgreSQL::getLayerMetadata");
#endif

if (this->layerMetaDataStore == nullptr) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a cache, right? The idea is to avoid multiple queries to the DB when this function gets called for different layers and metadataKey, right?

What if this function get called again with a different datasetName?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes it is cache, in this case for this dataset.

There are currently no cases for multiple datasets in one process.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That is true (as all the tests works...), but at the very least the function comments should make this very clear. Or be safe and implement the case by storing the values in a map bydatasetName.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That will be done in the follow up MR where we want to return all datasets with their layer info using one request.

#ifdef CDBAdapterPostgreSQL_DEBUG
CDBDebug("Need to query layer metadata for %s/%s/%s", datasetName, layerName, metadataKey);
#endif
CPGSQLDB *dataBaseConnection = getDataBaseConnection();
if (dataBaseConnection == NULL) {
return nullptr;
}

CT::string query;
if (datasetName != nullptr) {
if (CServerParams::checkForValidTokens(datasetName, "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_-:/.") == false) {
CDBError("Invalid dataset name. ");
throw(__LINE__);
}
query.print("SELECT datasetname, layername, metadatakey, blob FROM layermetadata WHERE datasetname = '%s';", datasetName);
} else {
query.print("SELECT datasetname, layername, metadatakey, blob FROM layermetadata");
}

this->layerMetaDataStore = dataBaseConnection->queryToStore(query.c_str());
if (layerMetaDataStore == nullptr) {
#ifdef CDBAdapterPostgreSQL_DEBUG
CDBDebug("Unable query: \"%s\"", query.c_str());
#endif
return nullptr;
}
}

#ifdef MEASURETIME
StopWatch_Stop("<CDBAdapterPostgreSQL::getLayerMetadata");
#endif
return layerMetaDataStore;
}

int CDBAdapterPostgreSQL::dropLayerFromLayerMetadataStore(const char *datasetName, const char *layerName) {
CPGSQLDB *dataBaseConnection = getDataBaseConnection();
if (dataBaseConnection == NULL) {
return -1;
}

CT::string query;
query.print("DELETE FROM layermetadata "
"WHERE datasetname='%s' AND layername = '%s';",
datasetName, layerName);
return dataBaseConnection->query(query.c_str());
}

bool CDBAdapterPostgreSQL::tryAdvisoryLock(size_t key) {
CPGSQLDB *dataBaseConnection = getDataBaseConnection();
if (dataBaseConnection == NULL) {
return false;
}
CT::string query;
query.print("SELECT pg_try_advisory_lock(%d) as \"result\";", key);
auto *store = dataBaseConnection->queryToStore(query.c_str());
if (store == nullptr || store->getSize() != 1) {
CDBError("Query failed [%s]:", dataBaseConnection->getError());
return false;
}
auto result = store->getRecord(0)->get("result");
bool succesfullylocked = result != nullptr && result->equals("t");
if (succesfullylocked) {
CDBDebug("pg_try_advisory_lock succesfullylocked");
} else {
CDBDebug("pg_try_advisory_lock NOT succesfullylocked");
}
delete store;
return succesfullylocked;
}

bool CDBAdapterPostgreSQL::advisoryUnLock(size_t key) {
CPGSQLDB *dataBaseConnection = getDataBaseConnection();
if (dataBaseConnection == NULL) {
return false;
}
CT::string query;

query.print("SELECT pg_advisory_unlock(%d) as \"result\";", key);
auto store = dataBaseConnection->queryToStore(query.c_str());
if (store == nullptr || store->getSize() != 1) {
CDBError("Query failed [%s]:", dataBaseConnection->getError());
return false;
}
auto result = store->getRecord(0)->get("result");
bool succesfullyunlocked = result != nullptr && result->equals("t");
if (succesfullyunlocked) {
CDBDebug("pg_advisory_unlock succesfullyunlocked");
} else {
CDBWarning("pg_advisory_unlock NOT succesfullyunlocked");
}
delete store;
return succesfullyunlocked;
}
Loading