From 3611e8bbfd45038eabce75e071817ef09e277a35 Mon Sep 17 00:00:00 2001 From: vlastahajek Date: Fri, 30 Sep 2022 13:58:32 +0200 Subject: [PATCH] fix: effective passing Point by value (#197) --- CHANGELOG.md | 4 +++ src/InfluxData.cpp | 4 +-- src/InfluxData.h | 6 ++-- src/InfluxDbClient.cpp | 18 +++++----- src/Point.cpp | 82 +++++++++++++++++++++++++----------------- src/Point.h | 27 +++++++++----- test/Test.cpp | 70 +++++++++++++++++++++++++++--------- test/Test.h | 1 + test/TestSupport.cpp | 13 +++++-- test/TestSupport.h | 6 ++++ test/test.ino | 11 +++--- 11 files changed, 162 insertions(+), 80 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fb8da21..02ff600 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,8 @@ # Changelog +## [unreleased] +### Fixes +- [198](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/198) - Effective passing Point by value + ## 3.12.1 [2022-08-29] ### Fixes - [193](https://github.com/tobiasschuerg/InfluxDB-Client-for-Arduino/pull/193) - Automatically adjusting point timestamp according to the setting of write precision. diff --git a/src/InfluxData.cpp b/src/InfluxData.cpp index 3e46615..992865a 100644 --- a/src/InfluxData.cpp +++ b/src/InfluxData.cpp @@ -29,8 +29,8 @@ void InfluxData::setTimestamp(long int seconds) { - _timestamp = timeStampToString(seconds,9); - strcat(_timestamp, "000000000"); + _data->timestamp = timeStampToString(seconds,9); + strcat(_data->timestamp, "000000000"); } String InfluxData::toString() const { diff --git a/src/InfluxData.h b/src/InfluxData.h index 2fa1b32..6fe1ec5 100644 --- a/src/InfluxData.h +++ b/src/InfluxData.h @@ -28,10 +28,10 @@ class InfluxData : public Point { public: - InfluxData(String measurement) : Point(measurement) {} + InfluxData(const String &measurement) : Point(measurement) {} - void addValue(String key, float value) { addField(key, value); } - void addValueString(String key, String value) { addField(key, value); } + void addValue(const String &key, float value) { addField(key, value); } + void addValueString(const String &key, String value) { addField(key, value); } void setTimestamp(long int seconds); String toString() const; }; diff --git a/src/InfluxDbClient.cpp b/src/InfluxDbClient.cpp index db42ce2..8a3353d 100644 --- a/src/InfluxDbClient.cpp +++ b/src/InfluxDbClient.cpp @@ -286,10 +286,10 @@ void InfluxDBClient::reserveBuffer(int size) { } void InfluxDBClient::addZerosToTimestamp(Point &point, int zeroes) { - char *ts = point._timestamp, *s; - point._timestamp = new char[strlen(point._timestamp) + 1 + zeroes]; - strcpy(point._timestamp, ts); - s = point._timestamp+strlen(ts); + char *ts = point._data->timestamp, *s; + point._data->timestamp = new char[strlen(point._data->timestamp) + 1 + zeroes]; + strcpy(point._data->timestamp, ts); + s = point._data->timestamp+strlen(ts); for(int i=0;itsWritePrecision != WritePrecision::NoTime && point._data->tsWritePrecision != _writeOptions._writePrecision) { + int diff = int(point._data->tsWritePrecision) - int(_writeOptions._writePrecision); if(diff > 0) { //point has higher precision, cut - point._timestamp[strlen(point._timestamp)-diff*3] = 0; + point._data->timestamp[strlen(point._data->timestamp)-diff*3] = 0; } else { //point has lower precision, add zeroes addZerosToTimestamp(point, diff*-3); } } // check someone set WritePrecision on point and not on client. NS precision is ok, cause it is default on server - } else if(point.hasTime() && point._tsWritePrecision != WritePrecision::NoTime && point._tsWritePrecision != WritePrecision::NS) { - int diff = int(WritePrecision::NS) - int(point._tsWritePrecision); + } else if(point.hasTime() && point._data->tsWritePrecision != WritePrecision::NoTime && point._data->tsWritePrecision != WritePrecision::NS) { + int diff = int(WritePrecision::NS) - int(point._data->tsWritePrecision); addZerosToTimestamp(point, diff*3); } } diff --git a/src/Point.cpp b/src/Point.cpp index 222e79c..b286b32 100644 --- a/src/Point.cpp +++ b/src/Point.cpp @@ -30,27 +30,45 @@ Point::Point(const String & measurement) { - _measurement = escapeKey(measurement, false); - _timestamp = nullptr; - _tsWritePrecision = WritePrecision::NoTime; + _data = std::make_shared(escapeKey(measurement, false)); } Point::~Point() { - delete [] _measurement; - delete [] _timestamp; +} + +Point::Data::Data(char * measurement) { + this->measurement = measurement; + timestamp = nullptr; + tsWritePrecision = WritePrecision::NoTime; +} + +Point::Data::~Data() { + delete [] measurement; + delete [] timestamp; +} + +Point::Point(const Point &other) { + *this = other; +} + +Point& Point::operator=(const Point &other) { + if(this != &other) { + this->_data = other._data; + } + return *this; } void Point::addTag(const String &name, String value) { - if(_tags.length() > 0) { - _tags += ','; - } - char *s = escapeKey(name); - _tags += s; - delete [] s; - _tags += '='; - s = escapeKey(value); - _tags += s; - delete [] s; + if(_data->tags.length() > 0) { + _data->tags += ','; + } + char *s = escapeKey(name); + _data->tags += s; + delete [] s; + _data->tags += '='; + s = escapeKey(value); + _data->tags += s; + delete [] s; } void Point::addField(const String &name, long long value) { @@ -114,14 +132,14 @@ void Point::addField(const String &name, const String &value) { } void Point::putField(const String &name, const String &value) { - if(_fields.length() > 0) { - _fields += ','; + if(_data->fields.length() > 0) { + _data->fields += ','; } char *s = escapeKey(name); - _fields += s; + _data->fields += s; delete [] s; - _fields += '='; - _fields += value; + _data->fields += '='; + _data->fields += value; } String Point::toLineProtocol(const String &includeTags) const { @@ -130,23 +148,23 @@ String Point::toLineProtocol(const String &includeTags) const { String Point::createLineProtocol(const String &incTags) const { String line; - line.reserve(strLen(_measurement) + 1 + incTags.length() + 1 + _tags.length() + 1 + _fields.length() + 1 + strLen(_timestamp)); - line += _measurement; + line.reserve(strLen(_data->measurement) + 1 + incTags.length() + 1 + _data->tags.length() + 1 + _data->fields.length() + 1 + strLen(_data->timestamp)); + line += _data->measurement; if(incTags.length()>0) { line += ","; line += incTags; } if(hasTags()) { line += ","; - line += _tags; + line += _data->tags; } if(hasFields()) { line += " "; - line += _fields; + line += _data->fields; } if(hasTime()) { line += " "; - line += _timestamp; + line += _data->timestamp; } return line; } @@ -172,7 +190,7 @@ void Point::setTime(WritePrecision precision) { setTime((char *)nullptr); break; } - _tsWritePrecision = precision; + _data->tsWritePrecision = precision; } void Point::setTime(unsigned long long timestamp) { @@ -188,16 +206,16 @@ void Point::setTime(const char *timestamp) { } void Point::setTime(char *timestamp) { - delete [] _timestamp; - _timestamp = timestamp; + delete [] _data->timestamp; + _data->timestamp = timestamp; } void Point::clearFields() { - _fields = (char *)nullptr; - delete [] _timestamp; - _timestamp = nullptr; + _data->fields = (char *)nullptr; + delete [] _data->timestamp; + _data->timestamp = nullptr; } void Point:: clearTags() { - _tags = (char *)nullptr; + _data->tags = (char *)nullptr; } diff --git a/src/Point.h b/src/Point.h index ca1c9e6..0df1a73 100644 --- a/src/Point.h +++ b/src/Point.h @@ -30,6 +30,7 @@ #include #include "WritePrecision.h" #include "util/helpers.h" +#include /** * Class Point represents InfluxDB point in line protocol. @@ -39,6 +40,8 @@ class Point { friend class InfluxDBClient; public: Point(const String &measurement); + Point(const Point &other); + Point& operator=(const Point &other); virtual ~Point(); // Adds string tag void addTag(const String &name, String value); @@ -70,21 +73,27 @@ friend class InfluxDBClient; // Clear tags void clearTags(); // True if a point contains at least one field. Points without a field cannot be written to db - bool hasFields() const { return _fields.length() > 0; } + bool hasFields() const { return _data->fields.length() > 0; } // True if a point contains at least one tag - bool hasTags() const { return _tags.length() > 0; } + bool hasTags() const { return _data->tags.length() > 0; } // True if a point contains timestamp - bool hasTime() const { return strLen(_timestamp) > 0; } + bool hasTime() const { return strLen(_data->timestamp) > 0; } // Creates line protocol with optionally added tags String toLineProtocol(const String &includeTags = "") const; // returns current timestamp - String getTime() const { return _timestamp; } + String getTime() const { return _data->timestamp; } protected: - char *_measurement; - String _tags; - String _fields; - char *_timestamp; - WritePrecision _tsWritePrecision; + class Data { + public: + Data(char *measurement); + ~Data(); + char *measurement; + String tags; + String fields; + char *timestamp; + WritePrecision tsWritePrecision; + }; + std::shared_ptr _data; protected: // method for formating field into line protocol void putField(const String &name, const String &value); diff --git a/test/Test.cpp b/test/Test.cpp index cb14fac..cc06398 100644 --- a/test/Test.cpp +++ b/test/Test.cpp @@ -30,7 +30,7 @@ #include #include "../src/Version.h" - +#include "InfluxData.h" #define INFLUXDB_CLIENT_TESTING_BAD_URL "http://127.0.0.1:999" @@ -41,6 +41,7 @@ void Test::run() { testUtils(); testOptions(); testPoint(); + testOldAPI(); testBatch(); testLineProtocol(); testEcaping(); @@ -48,6 +49,8 @@ void Test::run() { testIsValidID(); testFluxTypes(); testFluxTypesSerialization(); + testTimestampAdjustment(); + testFluxParserEmpty(); testFluxParserSingleTable(); testFluxParserNilValue(); @@ -71,7 +74,7 @@ void Test::run() { testLargeBatch(); testFailedWrites(); testTimestamp(); - testTimestampAdjustment(); + testRetryOnFailedConnection(); testRetryOnFailedConnectionWithFlush(); testNonRetry(); @@ -83,6 +86,7 @@ void Test::run() { testBuckets(); testQueryWithParams(); Serial.printf("Tests %s\n", failures ? "FAILED" : "SUCCEEDED"); + serverLog(TestBase::managementUrl, String("Tests ") + (failures ? "FAILED" : "SUCCEEDED")); } void Test::testUtils() { @@ -304,7 +308,7 @@ void Test::testPoint() { testLineTime = testLine + " " + snow + "123456789"; line = p.toLineProtocol(); TEST_ASSERTM(line == testLineTime, line); - now += 10; + now += 5; snow = ""; snow.concat(now); p.setTime(snow); @@ -353,6 +357,33 @@ void Test::testPoint() { TEST_ASSERT(!p.hasFields()); p.addField("nan", (double)NAN); TEST_ASSERT(!p.hasFields()); + + p.addField("a",1); + p.addTag("t","a"); + p.setTime(); + + Point p2 = p; + Point p3("a"); + + p3 = p2; + String lp = p2.toLineProtocol(); + String lp2 = p3.toLineProtocol(); + TEST_ASSERTM(lp == lp2, lp+","+lp2); + + TEST_END(); +} + +void Test::testOldAPI() { + TEST_INIT("testOldAPI"); + InfluxData d("a"), p("b"); + d.addValue("float", 1.1); + d.addValueString("string", "text"); + d.setTimestamp(1123456789l); + + p = d; + String lp = d.toString(); + String lp2 = p.toString(); + TEST_ASSERTM(lp == lp2, lp+","+lp2); TEST_END(); } @@ -399,6 +430,7 @@ void Test::testBatch() { TEST_ASSERT(buff[i++] == line[j]); } TEST_ASSERT(buff[i++] == '\n'); + delete [] buff; TEST_END(); } @@ -462,7 +494,7 @@ void Test::testLineProtocol() { line = client.pointToLineProtocol(p); TEST_ASSERTM(line == testLineTime, line); - now += 10; + now += 5; snow = ""; snow += now; p.setTime(snow); @@ -1309,11 +1341,15 @@ void Test::testTimestampAdjustment() { point.setTime(WritePrecision::NoTime); TEST_ASSERTM(!point.hasTime(), point.getTime() ); client.checkPrecisions(point); - TEST_ASSERTM(point.getTime().length() == 10, point.getTime() ); + int len = 10; + if(!WiFi.isConnected()) { + len = 1; + } + TEST_ASSERTM(point.getTime().length() == len, point.getTime() ); // test cut point.setTime(WritePrecision::US); client.checkPrecisions(point); - TEST_ASSERTM(point.getTime().length() == 10, point.getTime() ); + TEST_ASSERTM(point.getTime().length() == len, point.getTime() ); // test extending client.setWriteOptions(WriteOptions().writePrecision(WritePrecision::US)); point.setTime(WritePrecision::S); @@ -1476,25 +1512,25 @@ void Test::testFluxTypesSerialization() { struct strTest { FluxBase *fb; - const char *json; + const __FlashStringHelper * json; }; strTest tests[] = { - { new FluxLong("long", -2020123456), "\"long\":-2020123456" }, - { new FluxUnsignedLong("ulong", 2020123456), "\"ulong\":2020123456" }, - { new FluxBool("bool", false), "\"bool\":false"}, - { new FluxDouble("double", 28.3, 1), "\"double\":28.3"}, - { new FluxDateTime("dateTime", FluxDatatypeDatetimeRFC3339Nano, {15,34,9,22,4,120,0,0,0}, 123456), "\"dateTime\":\"2020-05-22T09:34:15.123456Z\""}, - { new FluxString("string", "my text", FluxDatatypeString), "\"string\":\"my text\""}, - { new FluxDouble("double", 21328.3132213,5), "\"double\":21328.31322"} + { new FluxLong("long", -2020123456), F("\"long\":-2020123456") }, + { new FluxUnsignedLong("ulong", 2020123456), F("\"ulong\":2020123456") }, + { new FluxBool("bool", false), F("\"bool\":false")}, + { new FluxDouble("double", 28.3, 1), F("\"double\":28.3")}, + { new FluxDateTime("dateTime", FluxDatatypeDatetimeRFC3339Nano, {15,34,9,22,4,120,0,0,0}, 123456), F("\"dateTime\":\"2020-05-22T09:34:15.123456Z\"")}, + { new FluxString("string", "my text", FluxDatatypeString), F("\"string\":\"my text\"")}, + { new FluxDouble("double", 21328.3132213,5), F("\"double\":21328.31322")}, + { new FluxString("duration", "-1h", FluxDatatypeDuration), F("\"duration\":\"-1h\"")} }; - for(int i=0;i<7;i++) { + for(int i=0;ijsonString(); delete tests[i].fb; - String json = buff; + TEST_ASSERTM(String(tests[i].json).equals(buff), buff); delete [] buff; - TEST_ASSERTM(json == tests[i].json , json); } TEST_END(); diff --git a/test/Test.h b/test/Test.h index 910aa42..8374985 100644 --- a/test/Test.h +++ b/test/Test.h @@ -41,6 +41,7 @@ class Test : public TestBase { static void testOptions(); static void testEcaping(); static void testPoint(); + static void testOldAPI(); static void testBatch(); static void testLineProtocol(); static void testFluxTypes(); diff --git a/test/TestSupport.cpp b/test/TestSupport.cpp index 8f062f3..1e1f93a 100644 --- a/test/TestSupport.cpp +++ b/test/TestSupport.cpp @@ -69,15 +69,24 @@ int httpGET(const String &url) { } bool deleteAll(const String &url) { - return httpPOST(url + "/api/v2/delete","") == 204; + if(WiFi.isConnected()) { + return httpPOST(url + "/api/v2/delete","") == 204; + } + return false; } bool serverLog(const String &url, String mess) { - return httpPOST(url + "/log", mess) == 204; + if(WiFi.isConnected()) { + return httpPOST(url + "/log", mess) == 204; + } + return false; } bool isServerUp(const String &url) { + if(WiFi.isConnected()) { return httpGET(url + "/status") == 200; + } + return false; } diff --git a/test/TestSupport.h b/test/TestSupport.h index 540a9e2..bc6df33 100644 --- a/test/TestSupport.h +++ b/test/TestSupport.h @@ -28,6 +28,12 @@ #ifndef _TEST_SUPPORT_H_ #define _TEST_SUPPORT_H_ +#if defined(ESP32) +#include +#elif defined(ESP8266) +#include +#endif + #include "query/FluxParser.h" void printFreeHeap(); diff --git a/test/test.ino b/test/test.ino index aec38a4..73710bc 100644 --- a/test/test.ino +++ b/test/test.ino @@ -51,22 +51,21 @@ void setup() { } void loop() { - uint32_t startRAM = ESP.getFreeHeap(); - Serial.printf("Start RAM: %d\n", startRAM); time_t now = time(nullptr); Serial.print("Start time: "); Serial.println(ctime(&now)); uint32_t start = millis(); - + uint32_t startRAM = ESP.getFreeHeap(); + Serial.printf("Start RAM: %d\n", startRAM); Test::run(); E2ETest::run(); - + uint32_t endRAM = ESP.getFreeHeap(); + Serial.printf("End RAM %d, diff: %d\n", endRAM, endRAM-startRAM); now = time(nullptr); Serial.print("End time: "); Serial.print(ctime(&now)); Serial.printf(" Took: %.1fs\n", (millis()-start)/1000.0f); - uint32_t endRAM = ESP.getFreeHeap(); - Serial.printf("End RAM %d, diff: %d\n", endRAM, endRAM-startRAM); + while(1) { delay(1000);