Skip to content

Commit 274867e

Browse files
committed
Merge remote-tracking branch 'origin/candidate-10.0.x' into candidate-10.2.x
Signed-off-by: Gordon Smith <GordonJSmith@gmail.com>
2 parents 4f0e005 + 2e4b9bd commit 274867e

File tree

32 files changed

+493
-183
lines changed

32 files changed

+493
-183
lines changed

.github/instructions/esp-service-interface.instructions.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@ applyTo: '**/*.ecm'
88
- Add a version attribute to any new or deprecated element.
99
- Use the next highest version number in the service's `*.ecm` file for versioning changes.
1010
- Increment the `version` and `default_client_version` attributes of the `ESPservice` element.
11-
- Include the `exceptions_inline` attribute in any new `ESPresponse` and `ESPmethod` element.
11+
- Include the `exceptions_inline` attribute in any new `ESPresponse` element.
12+
- Include the `exceptions_inline` attribute in any new `ESPmethod` element only if its parent `ESPservice` element doesn't have an `exceptions_inline` attribute.
1213

1314
## Naming Conventions
1415
- Use `PascalCase` for element names.

.github/workflows/build-clienttools-windows-2022.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -145,7 +145,7 @@ jobs:
145145
generateReleaseNotes: false
146146
prerelease: ${{ contains(github.ref, '-rc') }}
147147
makeLatest: ${{ inputs.make-latest }}
148-
artifacts: "${{ steps.build_clienttools.outputs.packages }}"
148+
artifacts: "./build/hpccsystems-clienttools-community*.exe"
149149

150150
- name: Release Internal Clienttools to JFrog Repository
151151
if: ${{ inputs.ln-ref != '' && github.repository_owner == 'hpcc-systems' }}

common/eventconsumption/eventdumpstream.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -493,10 +493,16 @@ class CDumpCSVEventVisitor : public CDumpStreamEventVisitor
493493
}
494494

495495
protected:
496-
// No attributes to be skipped at this time. Retain for possible future use.
497496
bool skipAttribute(unsigned id) const
498497
{
499-
return false;
498+
switch (id)
499+
{
500+
case EvAttrProcessDescriptor:
501+
// Only appears in RecordingSource, which is never visited.
502+
return true;
503+
default:
504+
return false;
505+
}
500506
}
501507

502508
virtual void recordAttribute(EventAttr id, const char*, const char* value, bool) override

common/eventconsumption/eventsaveas.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ bool CEventSavingOp::ready() const
5252
bool CEventSavingOp::doOp()
5353
{
5454
EventRecorder& recorder = queryRecorder();
55-
if (!recorder.startRecording(options, outputPath, false))
55+
if (!recorder.startRecording(options, outputPath, nullptr, 0, 0, 0, false))
5656
return false;
5757
Owned<IEventVisitor> terminalVisitor = new CEventSavingVisitor(*this);
5858
try

dali/base/dacsds.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2252,7 +2252,8 @@ unsigned CClientSDSManager::queryCount(const char *xpath)
22522252
#define MIN_UPDTENV_SVER "3.9"
22532253
bool CClientSDSManager::updateEnvironment(IPropertyTree *newEnv, bool forceGroupUpdate, StringBuffer &response)
22542254
{
2255-
CDaliVersion serverVersionNeeded(MIN_QUERYCOUNT_SVER);
2255+
// NB: legacy, and for bare-metal only
2256+
CDaliVersion serverVersionNeeded(MIN_UPDTENV_SVER);
22562257
if (queryDaliServerVersion().compare(serverVersionNeeded) < 0)
22572258
{
22582259
// have to do the old fashioned way, from client
@@ -2274,7 +2275,7 @@ bool CClientSDSManager::updateEnvironment(IPropertyTree *newEnv, bool forceGroup
22742275
conn->commit();
22752276
conn->close();
22762277
StringBuffer messages;
2277-
initClusterGroups(forceGroupUpdate, messages, oldEnvironment);
2278+
initClusterAndStoragePlaneGroups(messages, forceGroupUpdate, oldEnvironment);
22782279
if (messages.length())
22792280
PROGLOG("CClientSDSManager::updateEnvironment: %s", messages.str());
22802281
PROGLOG("Environment and node groups updated");

dali/base/dadfs.cpp

Lines changed: 117 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -10640,8 +10640,10 @@ class CInitGroups
1064010640
// see if identical
1064110641
const char *oldKind = oldClusterGroup->queryProp("@kind");
1064210642
const char *oldDir = oldClusterGroup->queryProp("@dir");
10643+
bool oldHasProtected = oldClusterGroup->hasProp("@protected");
1064310644
const char *newKind = newClusterGroup->queryProp("@kind");
1064410645
const char *newDir = newClusterGroup->queryProp("@dir");
10646+
bool newHasProtected = newClusterGroup->hasProp("@protected");
1064510647
if (oldKind)
1064610648
{
1064710649
if (newKind)
@@ -10666,7 +10668,15 @@ class CInitGroups
1066610668
}
1066710669
else if (NULL!=newDir)
1066810670
return false;
10669-
10671+
if (oldHasProtected != newHasProtected)
10672+
return false;
10673+
else if (oldHasProtected && newHasProtected)
10674+
{
10675+
bool oldProtected = oldClusterGroup->getPropBool("@protected");
10676+
bool newProtected = newClusterGroup->getPropBool("@protected");
10677+
if (oldProtected != newProtected)
10678+
return false;
10679+
}
1067010680
unsigned oldGroupCount = oldClusterGroup->getCount("Node");
1067110681
unsigned newGroupCount = newClusterGroup->getCount("Node");
1067210682
if (oldGroupCount != newGroupCount)
@@ -10912,6 +10922,7 @@ class CInitGroups
1091210922

1091310923
bool constructGroup(const IPropertyTree &cluster, const char *altName, IPropertyTree *oldEnvCluster, GroupType groupType, bool force, StringBuffer &messages)
1091410924
{
10925+
dbgassertex(!isContainerized());
1091510926
/* a 'realCluster' is a cluster who's name matches it's nodeGroup
1091610927
* if the nodeGroup differs it implies it's sharing the nodeGroup with other thor instance(s).
1091710928
*/
@@ -10955,6 +10966,10 @@ class CInitGroups
1095510966
IPropertyTree *existingClusterGroup = queryExistingGroup(gname);
1095610967
bool matchOldEnv = false;
1095710968
Owned<IPropertyTree> newClusterGroup = createClusterGroupFromEnvCluster(groupType, cluster, defDir, realCluster, true);
10969+
// All BM groups are protected by default, except dropzones.
10970+
// Meaning, they will not automatically be updated if the Environment cluster definition changes.
10971+
if (newClusterGroup && (grp_dropzone != groupType))
10972+
newClusterGroup->setPropBool("@protected", true);
1095810973
bool matchExisting = !force && clusterGroupCompare(newClusterGroup, existingClusterGroup);
1095910974
if (oldEnvCluster)
1096010975
{
@@ -10993,6 +11008,10 @@ class CInitGroups
1099311008
VStringBuffer msg("New cluster layout for cluster %s", gname.str());
1099411009
UWARNLOG("%s", msg.str());
1099511010
messages.append(msg).newline();
11011+
// All BM groups are protected by default, except dropzones.
11012+
// Meaning, they will not automatically be updated if the Environment cluster definition changes.
11013+
if (grp_dropzone != groupType)
11014+
newClusterGroup->setPropBool("@protected", true);
1099611015
addClusterGroup(gname.str(), newClusterGroup.getClear(), realCluster);
1099711016
return true;
1099811017
}
@@ -11019,6 +11038,7 @@ class CInitGroups
1101911038
if (ins>1)
1102011039
gname.append('_').append(ins);
1102111040
Owned<IPropertyTree> clusterGroup = createClusterGroup(grp_hthor, { na }, nullptr, &cluster, true, false);
11041+
clusterGroup->setPropBool("@protected", true);
1102211042
addClusterGroup(gname.str(), clusterGroup.getClear(), true);
1102311043
}
1102411044
}
@@ -11094,6 +11114,7 @@ class CInitGroups
1109411114
}
1109511115
bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &messages)
1109611116
{
11117+
dbgassertex(!isContainerized());
1109711118
Owned<IRemoteConnection> conn = querySDS().connect("/Environment", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
1109811119
if (!conn)
1109911120
return false;
@@ -11209,20 +11230,61 @@ class CInitGroups
1120911230
}
1121011231
return true;
1121111232
}
11212-
void clearLZGroups()
11233+
void clearUnprotectedGroups()
1121311234
{
1121411235
if (!writeLock)
11215-
throw makeStringException(0, "CInitGroups::clearLZGroups called in read-only mode");
11216-
IPropertyTree *root = groupsconnlock.conn->queryRoot();
11217-
std::vector<IPropertyTree *> toDelete;
11218-
Owned<IPropertyTreeIterator> groups = root->getElements("Group[@kind='dropzone']");
11236+
throw makeStringException(0, "CInitGroups::clearUnprotectedGroups called in read-only mode");
11237+
11238+
Owned<IPropertyTree> globalConfig = getGlobalConfig();
11239+
IPropertyTree * storage = globalConfig->queryPropTree("storage");
11240+
if (!storage)
11241+
return;
11242+
std::vector<IPropertyTree *> toRemove;
11243+
IPropertyTree *groupsRoot = groupsconnlock.conn->queryRoot();
11244+
Owned<IPropertyTreeIterator> groups = groupsRoot->getElements("Group");
11245+
bool firstBareMetalProtectedRun = true;
11246+
if (isContainerized())
11247+
firstBareMetalProtectedRun = false;
11248+
else
11249+
{
11250+
// check if any protected groups. Unless this is the 1st BM run since this feature was added,
11251+
// there will be >0 (one for each cluster group in the environment from previous runs).
11252+
ForEach(*groups)
11253+
{
11254+
IPropertyTree &group = groups->query();
11255+
if (group.hasProp("@protected"))
11256+
{
11257+
firstBareMetalProtectedRun = false;
11258+
break;
11259+
}
11260+
}
11261+
}
1121911262
ForEach(*groups)
11220-
toDelete.push_back(&groups->query());
11221-
for (auto &group: toDelete)
11222-
root->removeTree(group);
11263+
{
11264+
IPropertyTree &group = groups->query();
11265+
bool doDelete = false;
11266+
if (firstBareMetalProtectedRun)
11267+
{
11268+
doDelete = strsame("dropzone", group.queryProp("@kind"));
11269+
if (!doDelete)
11270+
{
11271+
// Protect all non dropzone BM groups created on 1st run
11272+
// This preserves legacy semantics, where Dali groups will not automatically be
11273+
// overwritten by a change in the topology in the environment.
11274+
group.setPropBool("@protected", true);
11275+
}
11276+
}
11277+
else
11278+
doDelete = !group.getPropBool("@protected");
11279+
if (doDelete)
11280+
toRemove.push_back(&group);
11281+
}
11282+
for (auto &group: toRemove)
11283+
groupsRoot->removeTree(group);
1122311284
}
1122411285
void constructGroups(bool force, StringBuffer &messages, IPropertyTree *oldEnvironment)
1122511286
{
11287+
dbgassertex(!isContainerized());
1122611288
Owned<IRemoteConnection> conn = querySDS().connect("/Environment/Software", myProcessSession(), RTM_LOCK_READ, SDS_CONNECT_TIMEOUT);
1122711289
if (!conn)
1122811290
return;
@@ -11301,11 +11363,13 @@ class CInitGroups
1130111363
return createClusterGroup(grp_unknown, hosts, path, nullptr, false, false);
1130211364
}
1130311365

11304-
void ensureConsistentStorageGroup(bool force, const char * name, IPropertyTree * newClusterGroup, StringBuffer & messages)
11366+
void ensureConsistentStorageGroup(const char * name, IPropertyTree * newClusterGroup, StringBuffer & messages)
1130511367
{
1130611368
IPropertyTree *existingClusterGroup = queryExistingGroup(name);
1130711369
bool matchExisting = clusterGroupCompare(newClusterGroup, existingClusterGroup);
11308-
if (!existingClusterGroup || !matchExisting)
11370+
bool oldProtected = existingClusterGroup ? existingClusterGroup->getPropBool("@protected") : false;
11371+
bool newProtected = newClusterGroup->getPropBool("@protected");
11372+
if (!existingClusterGroup || !matchExisting || (oldProtected != newProtected))
1130911373
{
1131011374
if (!existingClusterGroup)
1131111375
{
@@ -11314,7 +11378,7 @@ class CInitGroups
1131411378
messages.append(msg).newline();
1131511379
addClusterGroup(name, LINK(newClusterGroup), false);
1131611380
}
11317-
else if (force)
11381+
else if (!oldProtected || !newProtected) // i.e. allow overwrite if either old wasn't protected, or if was, but new isn't
1131811382
{
1131911383
VStringBuffer msg("Forcing new group layout for storageplane %s", name);
1132011384
UWARNLOG("%s", msg.str());
@@ -11330,17 +11394,7 @@ class CInitGroups
1133011394
}
1133111395
}
1133211396

11333-
void ensureStorageGroup(bool force, const char * name, unsigned numDevices, const char * path, StringBuffer & messages)
11334-
{
11335-
//Lower case the group name - see CNamedGroupStore::dolookup which lower cases before resolving.
11336-
StringBuffer gname;
11337-
gname.append(name).toLowerCase();
11338-
11339-
Owned<IPropertyTree> newClusterGroup = createStorageGroup(gname, numDevices, path);
11340-
ensureConsistentStorageGroup(force, gname, newClusterGroup, messages);
11341-
}
11342-
11343-
void constructStorageGroups(bool force, StringBuffer &messages)
11397+
void constructStorageGroups(StringBuffer &messages)
1134411398
{
1134511399
Owned<IPropertyTree> globalConfig = getGlobalConfig();
1134611400
IPropertyTree * storage = globalConfig->queryPropTree("storage");
@@ -11394,7 +11448,29 @@ class CInitGroups
1139411448
unsigned numDevices = plane.getPropInt("@numDevices", 1);
1139511449
newClusterGroup.setown(createStorageGroup(gname, numDevices, prefix));
1139611450
}
11397-
ensureConsistentStorageGroup(force, gname, newClusterGroup, messages);
11451+
// Storage planes are the single source of truth for storage layout.
11452+
// Dali groups are created to reflect storage plane definitions.
11453+
// If a plane definition changes, the corresponding Dali group is overwritten
11454+
// (with a warning issued).
11455+
//
11456+
// Setting @protectGroup=true on an individual plane prevents a changed plane
11457+
// definition from overwriting the existing Dali group layout.
11458+
//
11459+
// Note: For bare-metal Environment-based groups, the existing group is protected
11460+
// by default. In containerized environments, the plane definition always takes
11461+
// precedence unless it is explicitly protected.
11462+
//
11463+
// The @protectGroup option should only be used if existing logical files reference
11464+
// an old plane layout and there is a need to prevent them from pointing to a new group
11465+
// layout (which could make physical file parts inaccessible). However, such plane
11466+
// topology changes should be avoided. Instead, a new plane should be defined, with the
11467+
// existing plane definition being left untouched, so that existing files that reference
11468+
// it are unaffected.
11469+
if (plane.getPropBool("@protectGroup"))
11470+
newClusterGroup->setPropBool("@protected", true);
11471+
else
11472+
newClusterGroup->removeProp("@protected");
11473+
ensureConsistentStorageGroup(gname, newClusterGroup, messages);
1139811474
}
1139911475
}
1140011476
}
@@ -11411,31 +11487,29 @@ class CInitGroups
1141111487
}
1141211488
};
1141311489

11414-
void initClusterGroups(bool force, StringBuffer &response, IPropertyTree *oldEnvironment, unsigned timems)
11490+
void initClusterAndStoragePlaneGroups(StringBuffer &response, bool force, IPropertyTree *oldEnvironment, unsigned timems)
1141511491
{
1141611492
CInitGroups init(timems, true);
11417-
init.clearLZGroups(); // clear existing LZ groups, current ones will be recreated
11418-
init.constructGroups(force, response, oldEnvironment);
11419-
}
11420-
11421-
void initClusterAndStoragePlaneGroups(bool force, IPropertyTree *oldEnvironment, unsigned timems)
11422-
{
11423-
CInitGroups init(timems, true);
11424-
init.clearLZGroups(); // clear existing LZ groups, current ones will be recreated
11425-
11426-
StringBuffer response;
11427-
init.constructGroups(force, response, oldEnvironment);
11428-
if (response.length())
11429-
MLOG("DFS group initialization : %s", response.str()); // should this be a syslog?
11430-
11431-
response.clear();
11432-
init.constructStorageGroups(false, response);
11433-
if (response.length())
11434-
MLOG("StoragePlane group initialization : %s", response.str()); // should this be a syslog?
11493+
// clearUnprotectedGroups clears all unprotected groups - BM hthor, thor, roxie Environment groups are
11494+
// protected to maintain existing semantics, and to protect logical files which reference them.
11495+
init.clearUnprotectedGroups();
11496+
if (!isContainerized())
11497+
{
11498+
// Create groups based on the Environment
11499+
// Detects mismatches between existing Dali groups and new Environment definitions
11500+
// and avoids replacing them unless forced. This is to avoid situations where existing
11501+
// logical files reference existing groups, changing their definition may render the
11502+
// logical file parts inaccessible.
11503+
// NB: these groups derived from Environment, are tagged with @kind thor, roxie, hthor, dropzone etc.
11504+
init.constructGroups(force, response, oldEnvironment);
11505+
}
11506+
// Create storage plane groups based on the global config storage/planes definitions
11507+
init.constructStorageGroups(response);
1143511508
}
1143611509

1143711510
bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &response, unsigned timems)
1143811511
{
11512+
dbgassertex(!isContainerized());
1143911513
CInitGroups init(timems, true);
1144011514
return init.resetClusterGroup(clusterName, type, spares, response);
1144111515
}

dali/base/dadfs.hpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -877,8 +877,7 @@ interface IDaliServer;
877877
extern da_decl IDaliServer *createDaliDFSServer(); // called for coven members
878878

879879
// to initialize clustergroups after clusters change in the environment
880-
extern da_decl void initClusterGroups(bool force, StringBuffer &response, IPropertyTree *oldEnvironment, unsigned timems=INFINITE);
881-
extern da_decl void initClusterAndStoragePlaneGroups(bool force, IPropertyTree *oldEnvironment, unsigned timems=INFINITE);
880+
extern da_decl void initClusterAndStoragePlaneGroups(StringBuffer &response, bool force, IPropertyTree *oldEnvironment, unsigned timems=INFINITE);
882881
extern da_decl bool resetClusterGroup(const char *clusterName, const char *type, bool spares, StringBuffer &response, unsigned timems=INFINITE);
883882
extern da_decl bool addClusterSpares(const char *clusterName, const char *type, const std::vector<std::string> &hosts, StringBuffer &response, unsigned timems=INFINITE);
884883
extern da_decl bool removeClusterSpares(const char *clusterName, const char *type, const std::vector<std::string> &hosts, StringBuffer &response, unsigned timems=INFINITE);

dali/base/dasds.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6184,13 +6184,15 @@ static CConfigUpdateHook configUpdateHook;
61846184
static void initializeStorageGroups(IPropertyTree *oldEnvironment) // oldEnvironment always null in containerized
61856185
{
61866186
bool forceGroupUpdate = getComponentConfigSP()->getPropBool("dfs/@forceGroupUpdate");
6187-
initClusterAndStoragePlaneGroups(forceGroupUpdate, oldEnvironment);
6187+
StringBuffer response;
6188+
initClusterAndStoragePlaneGroups(response, forceGroupUpdate, oldEnvironment);
61886189
if (isContainerized())
61896190
{
61906191
auto updateFunc = [](const IPropertyTree *oldComponentConfiguration, const IPropertyTree *oldGlobalConfiguration)
61916192
{
61926193
bool forceGroupUpdate = getComponentConfigSP()->getPropBool("dfs/@forceGroupUpdate");
6193-
initClusterAndStoragePlaneGroups(forceGroupUpdate, nullptr);
6194+
StringBuffer response;
6195+
initClusterAndStoragePlaneGroups(response, forceGroupUpdate, nullptr);
61946196
};
61956197
configUpdateHook.installOnce(updateFunc, false);
61966198
}
@@ -8467,6 +8469,7 @@ void CCovenSDSManager::blockingSave(unsigned *writeTransactions)
84678469

84688470
bool CCovenSDSManager::updateEnvironment(IPropertyTree *newEnv, bool forceGroupUpdate, StringBuffer &response)
84698471
{
8472+
// for BM only
84708473
Owned<IRemoteConnection> conn = querySDS().connect("/",myProcessSession(),0, INFINITE);
84718474
if (conn)
84728475
{
@@ -8482,7 +8485,7 @@ bool CCovenSDSManager::updateEnvironment(IPropertyTree *newEnv, bool forceGroupU
84828485
conn->commit();
84838486
conn->close();
84848487
StringBuffer messages;
8485-
initClusterGroups(forceGroupUpdate, messages, oldEnvironment);
8488+
initClusterAndStoragePlaneGroups(messages, forceGroupUpdate, oldEnvironment);
84868489
response.append(messages);
84878490
PROGLOG("Environment and node groups updated");
84888491
}

0 commit comments

Comments
 (0)