diff --git a/common/workunit/wujobq.cpp b/common/workunit/wujobq.cpp index 8470cb154fc..6ac786c5608 100644 --- a/common/workunit/wujobq.cpp +++ b/common/workunit/wujobq.cpp @@ -1122,11 +1122,19 @@ class CJobQueue: public CJobQueueBase, implements IJobQueue void disconnect() // signal no longer wil be dequeing (optional - done automatically on release) { Cconnlockblock block(this,true); - if (connected) { + if (connected) + { dounsubscribe(); - ForEachQueue(qd) { + ForEachQueue(qd) + { IPropertyTree *croot = queryClientRootSession(*qd); - croot->setPropInt64("@connected",croot->getPropInt64("@connected",0)-1); + unsigned connectedCount = croot->getPropInt64("@connected"); + if (connectedCount) // should never be 0, but guard JIC + connectedCount--; + if (connectedCount) + croot->setPropInt64("@connected", connectedCount); + else + qd->root->removeTree(croot); } connected = false; } diff --git a/dali/base/dasds.cpp b/dali/base/dasds.cpp index 6ba9f68ad82..01605fcdd99 100644 --- a/dali/base/dasds.cpp +++ b/dali/base/dasds.cpp @@ -4938,6 +4938,18 @@ void initializeInternals(IPropertyTree *root) root->addPropTree("Status/Servers",createPTree()); } +void clearStaleMeteData(IPropertyTree *root) +{ + // JobQueues + // Remove all Client entries from all queues. By definition they are stale (they should normally be removed when the client disconnects) + Owned jobQueues = root->getElements("JobQueues/Queue"); + ForEach(*jobQueues) + { + IPropertyTree &queue = jobQueues->query(); + while (queue.removeProp("Client")); + } +} + IPropertyTree *loadStore(const char *storeFilename, unsigned edition, IPTreeMaker *iMaker, unsigned crcValidation, bool logErrorsOnly=false, const bool *abort=NULL) { CHECKEDCRITICALBLOCK(loadStoreCrit, fakeCritTimeout); @@ -6543,6 +6555,7 @@ void CCovenSDSManager::loadStore(const char *storeName, const bool *abort) } Owned conn = connect("/", 0, RTM_INTERNAL, INFINITE); initializeInternals(conn->queryRoot()); + clearStaleMeteData(conn->queryRoot()); conn.clear(); initializeStorageGroups(oldEnvironment); } diff --git a/esp/src/Login.html b/esp/src/Login.html index 42208eceae2..fcac7c377db 100644 --- a/esp/src/Login.html +++ b/esp/src/Login.html @@ -112,6 +112,8 @@ function (ready, nlsHPCCMod) { var nlsHPCC = nlsHPCCMod.default; ready(function () { + window.localStorage.setItem("redirectAfterLogin", window.location.hash); + var loginStr = document.getElementById("loginStr"); var error = document.getElementById("hidden_msg"); var disabled = document.getElementById('disabled_msg'); diff --git a/esp/src/package-lock.json b/esp/src/package-lock.json index bc4b85a6248..1a1d9ac0fbf 100644 --- a/esp/src/package-lock.json +++ b/esp/src/package-lock.json @@ -18,7 +18,7 @@ "@hpcc-js/chart": "2.83.3", "@hpcc-js/codemirror": "2.61.4", "@hpcc-js/common": "2.71.17", - "@hpcc-js/comms": "2.92.1", + "@hpcc-js/comms": "2.92.2", "@hpcc-js/dataflow": "8.1.6", "@hpcc-js/eclwatch": "2.74.3", "@hpcc-js/graph": "2.85.15", @@ -1855,9 +1855,9 @@ } }, "node_modules/@hpcc-js/comms": { - "version": "2.92.1", - "resolved": "https://registry.npmjs.org/@hpcc-js/comms/-/comms-2.92.1.tgz", - "integrity": "sha512-nx4JJUSpU1m/Yd53PsbEL26DQFx+3UF0Pelk5O0BY2eFGpPVaQ9jHeWvuMJCHHpHcbxUtWN5nlwZlZgE9CFptA==", + "version": "2.92.2", + "resolved": "https://registry.npmjs.org/@hpcc-js/comms/-/comms-2.92.2.tgz", + "integrity": "sha512-9AbPnCYuTF6OhbSiG5QMDA2vuF457YL88h2ltuxPOjsOxp9Dp5VFlTkh88vW1W3Yph/+faGhiqUSvLMgFIwXEA==", "dependencies": { "@hpcc-js/ddl-shim": "^2.20.6", "@hpcc-js/util": "^2.51.0", diff --git a/esp/src/package.json b/esp/src/package.json index f823572534d..b104c55aed4 100644 --- a/esp/src/package.json +++ b/esp/src/package.json @@ -44,7 +44,7 @@ "@hpcc-js/chart": "2.83.3", "@hpcc-js/codemirror": "2.61.4", "@hpcc-js/common": "2.71.17", - "@hpcc-js/comms": "2.92.1", + "@hpcc-js/comms": "2.92.2", "@hpcc-js/dataflow": "8.1.6", "@hpcc-js/eclwatch": "2.74.3", "@hpcc-js/graph": "2.85.15", diff --git a/esp/src/src-react/components/ECLPlayground.tsx b/esp/src/src-react/components/ECLPlayground.tsx index ecee18566cd..665e0c699ad 100644 --- a/esp/src/src-react/components/ECLPlayground.tsx +++ b/esp/src/src-react/components/ECLPlayground.tsx @@ -1,14 +1,17 @@ import * as React from "react"; import { ReflexContainer, ReflexElement, ReflexSplitter } from "../layouts/react-reflex"; -import { PrimaryButton, IconButton, IIconProps, Link, Dropdown, IDropdownOption, TextField, useTheme } from "@fluentui/react"; +import { IconButton, IIconProps, Link, Dropdown, IDropdownOption, TextField, useTheme } from "@fluentui/react"; +import { Button } from "@fluentui/react-components"; +import { CheckmarkCircleRegular, DismissCircleRegular, QuestionCircleRegular } from "@fluentui/react-icons"; import { scopedLogger } from "@hpcc-js/util"; import { useOnEvent } from "@fluentui/react-hooks"; import { mergeStyleSets } from "@fluentui/style-utilities"; import { ECLEditor, IPosition } from "@hpcc-js/codemirror"; -import { Workunit, WUUpdate } from "@hpcc-js/comms"; +import { Workunit, WUUpdate, WorkunitsService } from "@hpcc-js/comms"; import { HolyGrail } from "../layouts/HolyGrail"; import { DojoAdapter } from "../layouts/DojoAdapter"; import { pushUrl } from "../util/history"; +import { debounce } from "../util/throttle"; import { darkTheme } from "../themes"; import { InfoGrid } from "./InfoGrid"; import { TabbedResults } from "./Results"; @@ -77,6 +80,9 @@ const playgroundStyles = mergeStyleSets({ borderRight: borderStyle } }, + ".fui-Button": { + height: "min-content" + }, ".ms-Label": { marginRight: "12px" }, @@ -155,43 +161,58 @@ const warningIcon: IIconProps = { title: nlsHPCC.ErrorWarnings, ariaLabel: nlsHP const resultsIcon: IIconProps = { title: nlsHPCC.Outputs, ariaLabel: nlsHPCC.Outputs, iconName: "Table" }; const graphIcon: IIconProps = { title: nlsHPCC.Visualizations, ariaLabel: nlsHPCC.Visualizations, iconName: "BarChartVerticalFill" }; -const displayErrors = (wu, editor) => { +const displayErrors = async (wu = null, editor, errors = []) => { if (!editor) return; - wu.fetchECLExceptions().then(errors => { - errors.forEach(err => { - const lineError = err.LineNo; - const lineErrorNum = lineError > 0 ? lineError - 1 : 0; - const startPos: IPosition = { - ch: (err.Column > 0) ? err.Column - 1 : 0, - line: lineErrorNum - }; - const endPos: IPosition = { - ch: editor.getLineLength(lineErrorNum), - line: lineErrorNum - }; - - switch (err.Severity) { - case "Info": - editor.highlightInfo(startPos, endPos); - break; - case "Warning": - editor.highlightWarning(startPos, endPos); - break; - case "Error": - default: - editor.highlightError(startPos, endPos); - break; - } - }); + if (wu) { + errors = await wu.fetchECLExceptions(); + } + if (!errors.length) { + editor.removeAllHighlight(); + } + errors.forEach(err => { + const lineError = err.LineNo; + const lineErrorNum = lineError > 0 ? lineError - 1 : 0; + const startPos: IPosition = { + ch: (err.Column > 0) ? err.Column - 1 : 0, + line: lineErrorNum + }; + const endPos: IPosition = { + ch: editor.getLineLength(lineErrorNum), + line: lineErrorNum + }; + + switch (err.Severity) { + case "Info": + editor.highlightInfo(startPos, endPos); + break; + case "Warning": + editor.highlightWarning(startPos, endPos); + break; + case "Error": + default: + editor.highlightError(startPos, endPos); + break; + } }); }; +const service = new WorkunitsService({ baseUrl: "" }); + +enum SyntaxCheckResult { + Unknown, + Failed, + Passed +} + interface ECLEditorToolbarProps { editor: ECLEditor; outputMode: OutputMode; setOutputMode: (_: OutputMode) => void; workunit: Workunit; setWorkunit: (_: Workunit) => void; + setSyntaxErrors: (_: any) => void; + syntaxStatusIcon: number; + setSyntaxStatusIcon: (_: number) => void; } const ECLEditorToolbar: React.FunctionComponent = ({ @@ -199,7 +220,10 @@ const ECLEditorToolbar: React.FunctionComponent = ({ outputMode, setOutputMode, workunit, - setWorkunit + setWorkunit, + setSyntaxErrors, + syntaxStatusIcon, + setSyntaxStatusIcon }) => { const [cluster, setCluster] = React.useState(""); @@ -258,6 +282,24 @@ const ECLEditorToolbar: React.FunctionComponent = ({ } }, [cluster, editor, playgroundResults, queryName, setQueryNameErrorMsg]); + const checkSyntax = React.useCallback(() => { + service.WUSyntaxCheckECL({ + ECL: editor.ecl(), + Cluster: cluster + }).then(response => { + if (response.Errors) { + setSyntaxStatusIcon(SyntaxCheckResult.Failed); + setSyntaxErrors(response.Errors.ECLException); + displayErrors(null, editor, response.Errors.ECLException); + setOutputMode(OutputMode.ERRORS); + } else { + setSyntaxStatusIcon(SyntaxCheckResult.Passed); + setSyntaxErrors([]); + displayErrors(null, editor, []); + } + }); + }, [cluster, editor, setOutputMode, setSyntaxErrors, setSyntaxStatusIcon]); + const handleKeyUp = React.useCallback((evt) => { switch (evt.key) { case "Enter": @@ -282,10 +324,19 @@ const ECLEditorToolbar: React.FunctionComponent = ({ return
{showSubmitBtn ? ( - + ) : ( - + )} + = (props const [query, setQuery] = React.useState(""); const [selectedEclSample, setSelectedEclSample] = React.useState(""); const [eclContent, setEclContent] = React.useState(""); + const [syntaxErrors, setSyntaxErrors] = React.useState([]); + const [syntaxStatusIcon, setSyntaxStatusIcon] = React.useState(SyntaxCheckResult.Unknown); const [eclSamples, setEclSamples] = React.useState([]); React.useEffect(() => { @@ -417,6 +470,13 @@ export const ECLPlayground: React.FunctionComponent = (props }, [editor]); useOnEvent(document, "eclwatch-theme-toggle", handleThemeToggle); + const handleEclChange = React.useMemo(() => debounce((evt) => { + if (editor.hasFocus()) { + setSyntaxStatusIcon(SyntaxCheckResult.Unknown); + } + }, 300), [editor]); + useOnEvent(window, "keyup", handleEclChange); + return

{nlsHPCC.title_ECLPlayground}

@@ -437,7 +497,8 @@ export const ECLPlayground: React.FunctionComponent = (props main={} footer={ @@ -453,7 +514,7 @@ export const ECLPlayground: React.FunctionComponent = (props {outputMode === OutputMode.ERRORS ? ( - + ) : outputMode === OutputMode.RESULTS ? ( diff --git a/esp/src/src-react/components/InfoGrid.tsx b/esp/src/src-react/components/InfoGrid.tsx index 143cbf1be48..0689c515399 100644 --- a/esp/src/src-react/components/InfoGrid.tsx +++ b/esp/src/src-react/components/InfoGrid.tsx @@ -32,11 +32,13 @@ interface FilterCounts { } interface InfoGridProps { - wuid: string; + wuid?: string; + syntaxErrors?: any[]; } export const InfoGrid: React.FunctionComponent = ({ - wuid + wuid = null, + syntaxErrors = [] }) => { const [costChecked, setCostChecked] = React.useState(true); @@ -46,6 +48,7 @@ export const InfoGrid: React.FunctionComponent = ({ const [otherChecked, setOtherChecked] = React.useState(true); const [filterCounts, setFilterCounts] = React.useState({ cost: 0, penalty: 0, error: 0, warning: 0, info: 0, other: 0 }); const [exceptions] = useWorkunitExceptions(wuid); + const [errors, setErrors] = React.useState([]); const [data, setData] = React.useState([]); const { selection, setSelection, @@ -61,6 +64,14 @@ export const InfoGrid: React.FunctionComponent = ({ { key: "others", onRender: () => setOtherChecked(value)} styles={{ root: { paddingTop: 8, paddingRight: 8 } }} /> } ], [filterCounts.cost, filterCounts.error, filterCounts.info, filterCounts.other, filterCounts.warning]); + React.useEffect(() => { + if (syntaxErrors.length) { + setErrors(syntaxErrors); + } else { + setErrors(exceptions); + } + }, [syntaxErrors, exceptions]); + // Grid --- const columns = React.useMemo((): FluentColumns => { return { @@ -137,7 +148,7 @@ export const InfoGrid: React.FunctionComponent = ({ info: 0, other: 0 }; - const filteredExceptions = exceptions.map((row, idx) => { + const filteredExceptions = errors?.map((row, idx) => { if (row.Source === "Cost Optimizer") { row.Severity = "Cost"; } @@ -199,7 +210,7 @@ export const InfoGrid: React.FunctionComponent = ({ }); setData(filteredExceptions); setFilterCounts(filterCounts); - }, [costChecked, errorChecked, exceptions, infoChecked, otherChecked, warningChecked]); + }, [costChecked, errorChecked, errors, infoChecked, otherChecked, warningChecked]); React.useEffect(() => { if (data.length) { diff --git a/esp/src/src-react/components/Logs.tsx b/esp/src/src-react/components/Logs.tsx index 20cca36772c..d9703c0e74f 100644 --- a/esp/src/src-react/components/Logs.tsx +++ b/esp/src/src-react/components/Logs.tsx @@ -13,7 +13,7 @@ import { Filter } from "./forms/Filter"; import { Fields } from "./forms/Fields"; import { ShortVerticalDivider } from "./Common"; -const maximumTimeUntilRefresh = 8 * 60 * 60 * 1000; +const eightHours = 8 * 60 * 60 * 1000; const startTimeOffset = 1 * 60 * 60 * 1000; const endTimeOffset = 23 * 60 * 60 * 1000; const defaultStartDate = new Date(new Date().getTime() - startTimeOffset); @@ -116,8 +116,9 @@ export const Logs: React.FunctionComponent = ({ if (typeof filter.StartDate === "string") { filter.StartDate = new Date(filter.StartDate + ":00Z"); } - if (filter.StartDate && now.getTime() - filter.StartDate.getTime() > maximumTimeUntilRefresh) { - filter.StartDate = new Date(now.getTime() - startTimeOffset); + if (!filter.StartDate) { + //assign a reasonable default start date if one isn't set + filter.StartDate = new Date(now.getTime() - eightHours); } if (!filter.EndDate) { filter.EndDate = new Date(now.getTime() + endTimeOffset); diff --git a/esp/src/src-react/components/Queries.tsx b/esp/src/src-react/components/Queries.tsx index a0da7144844..e11938a5734 100644 --- a/esp/src/src-react/components/Queries.tsx +++ b/esp/src/src-react/components/Queries.tsx @@ -180,7 +180,7 @@ export const Queries: React.FunctionComponent = ({ const [DeleteConfirm, setShowDeleteConfirm] = useConfirm({ title: nlsHPCC.Delete, - message: nlsHPCC.DeleteSelectedWorkunits, + message: nlsHPCC.DeleteSelectedQueries, items: selection.map(s => s.Id), onSubmit: React.useCallback(() => { WsWorkunits.WUQuerysetQueryAction(selection, "Delete").then(() => refreshTable.call(true)); diff --git a/esp/src/src-react/components/QueryDetails.tsx b/esp/src/src-react/components/QueryDetails.tsx index af9ef819876..bbd2e3e969c 100644 --- a/esp/src/src-react/components/QueryDetails.tsx +++ b/esp/src/src-react/components/QueryDetails.tsx @@ -36,19 +36,23 @@ export const QueryDetails: React.FunctionComponent = ({ const [logicalFileCount, setLogicalFileCount] = React.useState(0); const [superFileCount, setSuperFileCount] = React.useState(0); const [libsUsedCount, setLibsUsedCount] = React.useState(0); + const [suspended, setSuspended] = React.useState(false); + const [activated, setActivated] = React.useState(false); React.useEffect(() => { setQuery(ESPQuery.Get(querySet, queryId)); }, [setQuery, queryId, querySet]); React.useEffect(() => { - query?.getDetails().then(({ WUQueryDetailsResponse }) => { + query?.getDetails().then(() => { setWuid(query.Wuid); setLogicalFileCount(query.LogicalFiles?.Item?.length); setSuperFileCount(query.SuperFiles?.SuperFile?.length); setLibsUsedCount(query.LibrariesUsed?.Item?.length); + setActivated(query.Activated); + setSuspended(query.Suspended); }); - }, [query, setLogicalFileCount, setSuperFileCount, setLibsUsedCount]); + }, [query]); const onTabSelect = React.useCallback((tab: TabInfo) => { switch (tab.id) { @@ -100,7 +104,7 @@ export const QueryDetails: React.FunctionComponent = ({
- + diff --git a/esp/src/src-react/components/QuerySummary.tsx b/esp/src/src-react/components/QuerySummary.tsx index 9e9869ddb95..1ce2df2109c 100644 --- a/esp/src/src-react/components/QuerySummary.tsx +++ b/esp/src/src-react/components/QuerySummary.tsx @@ -15,17 +15,20 @@ const logger = scopedLogger("../components/QuerySummary.tsx"); interface QuerySummaryProps { querySet: string; queryId: string; + isSuspended?: boolean; + isActivated?: boolean; } export const QuerySummary: React.FunctionComponent = ({ querySet, - queryId + queryId, + isSuspended = false, + isActivated = false }) => { const [query, setQuery] = React.useState(); - const [wuid, setWuid] = React.useState(""); - const [suspended, setSuspended] = React.useState(false); - const [activated, setActivated] = React.useState(false); + const [suspended, setSuspended] = React.useState(isSuspended); + const [activated, setActivated] = React.useState(isActivated); const [DeleteConfirm, setShowDeleteConfirm] = useConfirm({ title: nlsHPCC.Delete, @@ -57,12 +60,9 @@ export const QuerySummary: React.FunctionComponent = ({ }, [queryId, querySet]); React.useEffect(() => { - query?.getDetails().then(({ WUQueryDetailsResponse }) => { - setWuid(query?.Wuid); - setSuspended(query.Suspended); - setActivated(query.Activated); - }); - }, [query]); + setActivated(isActivated); + setSuspended(isSuspended); + }, [isActivated, isSuspended]); const buttons = React.useMemo((): ICommandBarItemProps[] => [ { @@ -73,7 +73,7 @@ export const QuerySummary: React.FunctionComponent = ({ { key: "save", text: nlsHPCC.Save, iconProps: { iconName: "Save" }, disabled: !canSave, onClick: () => { - const selection = [{ QuerySetId: querySet, Id: queryId }]; + const selection = [{ QuerySetId: querySet, Id: queryId, Name: query?.QueryName }]; const actions = []; if (suspended !== query?.Suspended) { actions.push(WsWorkunits.WUQuerysetQueryAction(selection, suspended ? "Suspend" : "Unsuspend")); @@ -125,7 +125,7 @@ export const QuerySummary: React.FunctionComponent = ({ }} /> {nlsHPCC.Workunit} {nlsHPCC.Other} diff --git a/esp/src/src/Session.ts b/esp/src/src/Session.ts index 281742e4b13..f7a43044e3d 100644 --- a/esp/src/src/Session.ts +++ b/esp/src/src/Session.ts @@ -6,7 +6,7 @@ import { SMCService } from "@hpcc-js/comms"; import { scopedLogger } from "@hpcc-js/util"; import { cookieKeyValStore, sessionKeyValStore, userKeyValStore } from "src/KeyValStore"; import { singletonDebounce } from "../src-react/util/throttle"; -import { parseSearch } from "../src-react/util/history"; +import { parseSearch, replaceUrl } from "../src-react/util/history"; import { ModernMode } from "./BuildInfo"; import * as ESPUtil from "./ESPUtil"; @@ -135,6 +135,11 @@ export function formatCost(value): string { export function initSession() { if (sessionIsActive > -1) { + const redirectUrl = window.localStorage.getItem("redirectAfterLogin") ?? ""; + if (redirectUrl) { + window.localStorage.removeItem("redirectAfterLogin"); + replaceUrl(redirectUrl); + } idleWatcher.on("active", function () { resetESPTime(); }); diff --git a/esp/src/src/nls/hpcc.ts b/esp/src/src/nls/hpcc.ts index 360ba2801c2..d864130fb48 100644 --- a/esp/src/src/nls/hpcc.ts +++ b/esp/src/src/nls/hpcc.ts @@ -936,6 +936,7 @@ export = { Statistics: "Statistics", SVGSource: "SVG Source", SyncSelection: "Sync To Selection", + Syntax: "Syntax", SystemServers: "System Servers", tag: "tag", Target: "Target", diff --git a/system/jlib/jsocket.cpp b/system/jlib/jsocket.cpp index 4142a6bd125..5ecd2369205 100644 --- a/system/jlib/jsocket.cpp +++ b/system/jlib/jsocket.cpp @@ -363,9 +363,6 @@ struct xfd_set { __fd_mask fds_bits[XFD_SETSIZE / __NFDBITS]; }; // define our o #define T_SOCKET int #define SEND_FLAGS (MSG_NOSIGNAL) #endif -#ifdef CENTRAL_NODE_RANDOM_DELAY -static SocketEndpointArray CentralNodeArray; -#endif enum SOCKETMODE { sm_tcp_server, sm_tcp, sm_udp_server, sm_udp, sm_multicast_server, sm_multicast}; #define BADSOCKERR(err) ((err==JSE_BADF)||(err==JSE_NOTSOCK)) @@ -1538,20 +1535,8 @@ void CSocket::connect_wait(unsigned timems) bool exit = false; int err; unsigned refuseddelay = 1; - while (!exit) { -#ifdef CENTRAL_NODE_RANDOM_DELAY - ForEachItemIn(cn,CentralNodeArray) { - const SocketEndpoint &ep=CentralNodeArray.item(cn); - if (ep.ipequals(targetip)) { - unsigned sleeptime = getRandom() % 1000; - StringBuffer s; - ep.getHostText(s); - DBGLOG("Connection to central node %s - sleeping %d milliseconds", s.str(), sleeptime); - Sleep(sleeptime); - break; - } - } -#endif + while (!exit) + { unsigned remaining; exit = tm.timedout(&remaining); bool blockselect = exit; // if last time round block @@ -6051,15 +6036,6 @@ ISocketBufferReader *createSocketBufferReader(const char *trc) } -extern jlib_decl void markNodeCentral(SocketEndpoint &ep) -{ -#ifdef CENTRAL_NODE_RANDOM_DELAY - CriticalBlock block(CSocket::crit); - CentralNodeArray.append(ep); -#endif -} - - static CSocket *prepareSocket(unsigned idx,const SocketEndpoint &ep, ISocketConnectNotify &inotify) { Owned sock = new CSocket(ep,sm_tcp,NULL); diff --git a/system/jlib/jsocket.hpp b/system/jlib/jsocket.hpp index bf91c86a3b7..8b82a1d9d8e 100644 --- a/system/jlib/jsocket.hpp +++ b/system/jlib/jsocket.hpp @@ -76,7 +76,6 @@ enum JSOCKET_ERROR_CODES { #ifndef _WIN32 #define BLOCK_POLLED_SINGLE_CONNECTS // NB this is much slower in windows -#define CENTRAL_NODE_RANDOM_DELAY #else #define USERECVSEM // to singlethread BF_SYNC_TRANSFER_PUSH #endif @@ -637,8 +636,6 @@ interface ISocketBufferReader: extends IInterface extern jlib_decl ISocketBufferReader *createSocketBufferReader(const char *trc=NULL); -extern jlib_decl void markNodeCentral(SocketEndpoint &ep); // random delay for linux - interface ISocketConnectNotify { public: diff --git a/system/mp/mpcomm.cpp b/system/mp/mpcomm.cpp index 6355baa5a15..6caa83f8e14 100644 --- a/system/mp/mpcomm.cpp +++ b/system/mp/mpcomm.cpp @@ -2165,6 +2165,11 @@ CMPConnectThread::CMPConnectThread(CMPServer *_parent, unsigned port, bool _list parent->mpTraceLevel = getComponentConfigSP()->getPropInt("logging/@detail", InfoMsgThreshold); if (listen) { + if (getComponentConfigSP()->hasProp("expert/@mpSoMaxConn")) + mpSoMaxConn = getComponentConfigSP()->getPropInt("expert/@mpSoMaxConn"); + else + mpSoMaxConn = getGlobalConfigSP()->getPropInt("expert/@mpSoMaxConn", 0); + if (getComponentConfigSP()->hasProp("expert/@acceptThreadPoolSize")) acceptThreadPoolSize = getComponentConfigSP()->getPropInt("expert/@acceptThreadPoolSize"); else diff --git a/thorlcr/graph/thgraphslave.cpp b/thorlcr/graph/thgraphslave.cpp index 3974042bc12..14c8d7ea6d0 100644 --- a/thorlcr/graph/thgraphslave.cpp +++ b/thorlcr/graph/thgraphslave.cpp @@ -1255,6 +1255,8 @@ void CSlaveGraph::executeSubGraph(size32_t parentExtractSz, const byte *parentEx void CSlaveGraph::abort(IException *e) { + if (aborted) + return; if (!graphDone) // set pre done(), no need to abort if got that far. CGraphBase::abort(e); getDoneSem.signal(); @@ -1262,23 +1264,27 @@ void CSlaveGraph::abort(IException *e) void CSlaveGraph::done() { - GraphPrintLog("End of sub-graph"); - progressActive.store(false); - setProgressUpdated(); // NB: ensure collected after end of graph - if (!queryOwner() || isGlobal()) + if (started) { - if (aborted || !graphDone) + GraphPrintLog("End of sub-graph"); + progressActive.store(false); + setProgressUpdated(); // NB: ensure collected after end of graph + + if (initialized && (!queryOwner() || isGlobal())) { - if (!getDoneSem.wait(SHORTTIMEOUT)) // wait on master to clear up, gather info from slaves - WARNLOG("CSlaveGraph::done - timedout waiting for master to signal done()"); + if (aborted || !graphDone) + { + if (!getDoneSem.wait(SHORTTIMEOUT)) // wait on master to clear up, gather info from slaves + WARNLOG("CSlaveGraph::done - timedout waiting for master to signal done()"); + } + else + getDoneSem.wait(); + } + if (!queryOwner()) + { + if (globals->getPropBool("@watchdogProgressEnabled")) + jobS->queryProgressHandler()->stopGraph(*this, NULL); } - else - getDoneSem.wait(); - } - if (!queryOwner()) - { - if (globals->getPropBool("@watchdogProgressEnabled")) - jobS->queryProgressHandler()->stopGraph(*this, NULL); } Owned exception; diff --git a/thorlcr/slave/thslavemain.cpp b/thorlcr/slave/thslavemain.cpp index 2d2e43de2fb..c1fa682a57c 100644 --- a/thorlcr/slave/thslavemain.cpp +++ b/thorlcr/slave/thslavemain.cpp @@ -436,7 +436,6 @@ int main( int argc, const char *argv[] ) SocketEndpoint masterEp(master); localHostToNIC(masterEp); setMasterPortBase(masterEp.port); - markNodeCentral(masterEp); if (RegisterSelf(masterEp)) {