HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
PDG_Service.h
Go to the documentation of this file.
1 /*
2  * PROPRIETARY INFORMATION. This software is proprietary to
3  * Side Effects Software Inc., and is not to be reproduced,
4  * transmitted, or disclosed in any way without written permission.
5  *
6  * COMMENTS:
7  */
8 
9 #ifndef __PDG_SERVICE_H__
10 #define __PDG_SERVICE_H__
11 
12 #include "PDG_API.h"
13 #include "PDG_RegisteredType.h"
14 #include "PDG_ServiceTypes.h"
15 #include "PDG_WorkItemTypes.h"
16 
17 #include <PDGT/PDGT_ValueArgs.h>
18 
19 #include <UT/UT_Array.h>
20 #include <UT/UT_ConcurrentSet.h>
21 #include <UT/UT_Lock.h>
22 #include <UT/UT_StringArray.h>
23 #include <UT/UT_StringHolder.h>
24 #include <UT/UT_UniquePtr.h>
25 
26 class PDG_Scheduler;
27 class PY_PyObject;
28 class UT_Thread;
29 class UT_WorkBuffer;
30 
31 namespace PDGN
32 {
33  class PDGN_Message;
34  class PDGN_PollingClientNNG;
35 }
36 
37 /*
38  * Represents a registered service object, tracks the list of active clients
39  * for the service, and keeps track of various settings like the service
40  * pool size, MQ connection information, and service state.
41  */
43 {
44 public:
45  /// Service data format version
47 
48  /// Enumeration of return codes from acquireClient
50  {
51  /// A service client was successfully acquired
53 
54  /// A service client was successfully acquired and locked
56 
57  /// All service workers are already busy
59 
60  /// The service worker is aleady in use by a different task
61  /// with the same service lock id
63 
64  /// The service lock is invalid -- should never occur in practice
66  };
67 
68  /// Service client array entry
69  struct ClientInfo
70  {
71  /// Constructs a new client info instance
72  ClientInfo(
73  const PDG_Service* service,
74  const UT_StringHolder& server_address,
75  int server_port,
76  int client_num);
77 
78  /// Constructs an incomplete client instance -- this is used for
79  /// compatbility with older version of Houdini that did not
80  /// explicitly track client info
81  ClientInfo(const UT_StringHolder& client_name);
82 
83  /// Returns the command for the client as a string, but combining the
84  /// command arguments
85  UT_StringHolder commandString() const;
86 
87  /// Spawns the client as a child process, and returns true on
88  /// success
89  bool spawnProcess();
90 
91  /// /// Kills the active client process, if one exists
92  void killProcess();
93 
94 
95  /// The array of command line args for the client
97 
98  /// The name of the service client
100 
101  /// The log path for client output
103 
104  /// The connection address
106 
107 
108  /// The connection port
110 
111  /// The process or job id for the client
113 
114  /// The total number of tasks the service has cooked
116 
117  /// The amount of memory in use by the process, as recorded by the
118  /// last task that cooked using the client
120 
121  /// The ID of the work item that has locked the service client, if
122  /// any
124 
125  /// Set to true once the client has connected
127 
128  /// Set to true if the client is active for a job
130  };
131 
132 public:
133 
134  /// Constructs a new service instance with a default pool size of 1, and
135  /// no connection information.
136  PDG_Service(
137  const PDG_BaseType* type,
138  const PDGT_ValueArgs& extra_args,
139  const UT_StringHolder& service_command,
140  bool internal_service);
141 
142  ~PDG_Service() override;
143 
144  /// Sets/gets the unique name for the service. The name of the service is
145  /// unique to the PDG_ServiceManager that created it.
147  { myName = name; }
148  const UT_StringHolder& name() const
149  { return myName; }
150 
151  /// Returns true if the service is internal to PDG. Internal services
152  /// cannot be directly managed by users.
153  bool isInternal() const
154  { return myIsInternal; }
155 
156  /// Sets/gets the persistent flag, which determines whether a service
157  /// should be persisted to the pdgservice JSON configuration file. A
158  /// service that isn't persistent will be lost when the Houdini session
159  /// is closed.
160  void setPersistent(bool persistent)
161  { myIsPersistent = persistent; }
162  bool isPersistent() const
163  { return myIsPersistent; }
164 
165  /// Returns true if the service has errors when starting
166  bool hasErrors() const
167  { return myHasErrors; }
168 
169  /// Sets/gets the autostart flag, which indicates that the service will
170  /// start automatically when work items need to use it.
171  void setAutoStart(bool auto_start)
172  { myIsAutoStart = auto_start; }
173  bool isAutoStart() const
174  { return myIsAutoStart; }
175 
176  /// Sets/gets an opaque Python data object that can be stored on the
177  /// service.
178  void setData(PY_PyObject* new_data);
180  { return myData; }
181 
182  /// Sets/gets the MQ url that the service should use to relay messages
183  /// between service clients and the PDG graph
184  void setMqUrl(const UT_StringHolder& url)
185  { myMqUrl = url; }
186  const UT_StringHolder& mqUrl() const
187  { return myMqUrl; }
188 
189  /// Sets/gets the log level for the MQ process that relays messages
190  /// between clients and the PDG graph
191  void setMqLogLevel(int log_level)
192  { myMqLogLevel = log_level; }
193  int mqLogLevel() const
194  { return myMqLogLevel; }
195 
196  /// Sets/gets the port used by the MQ relay.
197  void setMqPort(int mq_port)
198  { myMqPort = mq_port; }
199  int mqPort() const
200  { return myMqPort; }
201 
202  /// Sets/gets the directory that service clients should write their log
203  /// files to.
204  void setClientLogDir(const UT_StringHolder& log_dir)
205  { myClientLogDir = log_dir; }
207  { return myClientLogDir; }
208 
209  /// Sets/gets the directory that the MQ relay writes its logs to.
210  void setMqLogDir(const UT_StringHolder& log_dir)
211  { myMqLogDir = log_dir; }
212  const UT_StringHolder& mqLogDir() const
213  { return myMqLogDir; }
214 
215  /// Sets how the service itself should log output
217  { myClientLogType = log_type; }
219  { return myClientLogType; }
220 
221  /// Sets/gets the names for the environment variables to be set in
222  /// this job's environment. This only applies if the service does not
223  /// have a scheduler.
224  void setEnvVarNames(const UT_StringArray& env_var_names)
225  { myEnvVarNames = env_var_names; }
227  { return myEnvVarNames; }
228 
229  /// Sets/gets the values for the environment variables to be set in
230  /// this job's environment. This only applies if the service does not
231  /// have a scheduler.
232  void setEnvVarValues(const UT_StringArray& env_var_values)
233  { myEnvVarValues = env_var_values; }
235  { return myEnvVarValues; }
236 
237  /// Sets/gets the extra args array for the service
239  { myExtraArguments = args; }
241  { return myExtraArguments; }
242 
243  /// For scheduler services, sets the name of the scheduler and graph
244  /// that created the service.
245  void setScheduler(
246  const UT_StringHolder& name,
247  const UT_StringHolder& context_name);
248 
249  /// Clears the scheduler information associated with a scheduler
250  /// service
251  void clearScheduler();
252 
253  /// Returns the name of the scheduler associated with the service, if
254  /// it's a scheduler service
256  { return mySchedulerName; }
257 
258  /// Returns the name of the graph that owns the scheduler that created
259  /// the service, if it's a scheduler service
261  { return mySchedulerContextName; }
262 
263  /// Sets/gets the service owner type -- either a session service or a
264  /// scheduler service
266  { myServiceOwner = owner; }
268  { return myServiceOwner; }
269 
270  /// Sets/gets the current state of the service
272  { myState = state; }
274  { return myState; }
275 
276  /// Sets/gets the command line string that should be used to start clients
277  /// running in the service pool
278  void setCommand(const UT_StringHolder& command)
279  { myCommand = command; }
280  const UT_StringHolder& command() const
281  { return myCommand; }
282 
283  /// Sets/gets the pool size for the service, which determines the number
284  /// of concurrent client processes that service executes
285  void setPoolSize(int pool_size)
286  { myPoolSize = pool_size; }
287  int poolSize() const
288  { return myPoolSize; }
289 
290  /// Sets/gets the connection port for the service itself
291  void setPort(int port)
292  { myPort = port; }
293  int port() const
294  { return myPort; }
295 
296  /// Sets the service connection timeout in milliseconds
297  void setConnectionTimeout(int ms)
298  { myConnectionTimeout = ms; }
299  int connectionTimeout() const
300  { return myConnectionTimeout; }
301 
302  /// Sets the memory limit and reset type for the service
304  PDG_ServiceResetType memory_reset_type)
305  {
306  myMemoryResetType = memory_reset_type;
307  }
309  exint memory_limit)
310  {
311  myMemoryLimit = memory_limit;
312  }
314  { return myMemoryResetType; }
316  { return myMemoryLimit; }
317 
318  /// Returns true if the service is start or is already running
319  bool isStartingOrRunning() const;
320 
321  /// Returns true if the service is stopping, or has already stopped
322  bool isStoppingOrStopped() const;
323 
324  /// Queries and returns the scheduler associated with the service, if the
325  /// service is a scheduler service
326  PDG_Scheduler* serviceScheduler(UT_WorkBuffer& errors) const;
327 
328 
329  /// Queries the list of all active service client names
330  UT_StringArray clientNames() const;
331 
332  /// Queries the name of a particular service client, using its client
333  /// number
334  UT_StringHolder clientName(int client_num) const;
335 
336  /// Returns the service client info for a particular client
337  ClientInfo* client(const UT_StringHolder& name);
338 
339  /// Adds a pending service client, which can be waiting on using
340  /// waitForClients
341  ClientInfo* addPendingClient(
342  const UT_StringHolder& server_address,
343  int server_port,
344  int client_num);
345 
346 
347  /// Stats a service pool. If background is true the service processes are
348  /// start asynchronously, and control immediately returns after calling
349  /// this function. It's up to the caller to ensure that the service has
350  /// started before using it. Returns either success, failure, or already-
351  /// running.
352  PDG_ServiceStartResult startService(
353  UT_WorkBuffer& errors,
354  bool background);
355 
356  /// Resets a specific service client, or all clients if empty string is
357  /// passed in as the client_name
358  bool resetClient(
359  UT_WorkBuffer& errors,
360  const UT_StringHolder& client_name =
362 
363  /// Restarts a service client. If client_name is empty string all
364  /// clients are restarted.
365  bool restartClient(
366  UT_WorkBuffer& errors,
367  const UT_StringHolder& client_name);
368 
369  /// Stops a service client and kills the process associated with it.
370  /// The client can be started again at a later point using restartClient.
371  /// If client_name is empty string all clients are stoppped.
372  bool stopClient(
373  UT_WorkBuffer& errors,
374  const UT_StringHolder& client_name);
375 
376  /// Immediately kills the process associated with a service client.
377  /// The client can be started again at a later point using restartClient.
378  /// If client_name is empty string all clients are stoppped.
379  bool killClient(
380  UT_WorkBuffer& errors,
381  const UT_StringHolder& client_name);
382 
383  /// Stops the service if it's running, and returns a boolean to indiate
384  /// the status.
385  bool stopService(
386  UT_WorkBuffer& errors,
387  bool ignore_stopped);
388 
389  /// Kills the service if it's running, and returns a boolean to indiate
390  /// the status.
391  bool killService(
392  UT_WorkBuffer& errors,
393  bool ignore_stopped);
394 
395  /// Cleans up the clients in the service. This method is public so that
396  /// schedulers can call it on services they manage.
397  bool cleanupService(
398  UT_WorkBuffer& errors,
399  bool stop_mq_server,
400  bool wait_for_clients);
401 
402  /// Submits a work item to a service client asynchronously, and returns
403  /// the pending message handle for the job.
404  PDGN::PDGN_Message* executeWorkItem(
405  UT_WorkBuffer& errors,
406  const UT_StringHolder& client_name,
407  const PDG_WorkItem* work_item);
408 
409  /// Submits a work item to a service client asychronously, and returns
410  /// the pending messae handle for the job. This variant of the method
411  /// allows the caller to supply a custom script that will run instead of
412  /// the standard job script or script data associated with the work item.
413  PDGN::PDGN_Message* executeWorkItem(
414  UT_WorkBuffer& errors,
415  const UT_StringHolder& client_name,
416  const PDG_WorkItem* work_item,
417  const UT_WorkBuffer& script_buffer);
418 
419  /// Starts a background thread that polls the ready listener until all
420  /// service clients have connected
421  void startPollingClient();
422 
423  /// This will force stop the ready listener. If you want to wait for it to
424  /// complete, you should call waitForClients() instead.
425  void stopPollingClient();
426 
427  /// Returns the name of the polling client, if one exists
428  const UT_StringHolder& pollingClientName() const;
429 
430  /// Returns true if the service has an active polling client
431  bool hasPollingClient() const
432  { return (myPollingClient != nullptr); }
433 
434  // Returns a pointer to the polling client, or nullptr if none exists.
435  PDGN::PDGN_PollingClientNNG*
437  { return myPollingClient.get(); }
438 
439  /// Waits for all pending service clients to connect, and then terminates
440  /// the ready listener
441  void waitForClients();
442 
443  /// Increments the number of actively starting client
444  void incrementStartingClientsCount();
445 
446  /// Returns the command for the service client with the specified client
447  /// number, as a string.
448  UT_StringHolder getCommand(
449  const char* server_address,
450  int server_port,
451  int client_num) const;
452 
453  /// Returns the command for the service client with the specified client
454  /// number, as an array of arguments
455  void getCommand(
456  UT_StringArray& command_tokens,
457  const char* server_address,
458  int server_port,
459  int client_num) const;
460 
461  /// Pings the specified client, and returns true if the client was
462  /// reachable
463  bool ping(int client_num, UT_WorkBuffer& errors) const;
464 
465  /// Acquires a client, which reserves it for the caller
466  ServiceAcquireResult acquireClient(
467  UT_StringHolder& client_name,
468  PDG_WorkItemID item_lock);
469 
470  /// Releases a client that was previously acquired, but does not unlock it
471  bool releaseClient(
472  UT_WorkBuffer& errors,
473  const UT_StringHolder& client_name,
474  PDG_ServiceResetWhen reset_when,
475  PDG_ServiceResetType reset_type,
476  int64 memory_usage);
477 
478  /// Unlocks a service client
479  bool unlockClient(
480  PDG_WorkItemID item_lock,
481  PDG_ServiceResetType reset_type,
482  UT_WorkBuffer& errors);
483 
484 private:
485  enum ClientCleanupType
486  {
487  eClientCleanupNone,
488  eClientCleanupWait,
489  eClientCleanupKill
490  };
491 
492  static void* runSpawnSessionService(void* param);
493  static void* runPollingThread(void* param);
494 
495  bool getClientNameFromMessage(
496  PDGN::PDGN_Message* msg,
497  UT_StringHolder& client_name);
498 
499  bool startSessionService(
500  UT_WorkBuffer& errors,
501  bool background);
502  bool spawnSessionServiceClients();
503  void pollClients();
504 
505  bool stopService(
506  UT_WorkBuffer& errors,
507  ClientCleanupType cleanup_type,
508  bool ignore_stopped);
509  bool stopSessionService(
510  UT_WorkBuffer& errors,
511  ClientCleanupType cleanup_type);
512  bool stopClient(
513  UT_WorkBuffer& errors,
514  int client_index,
515  bool restart);
516  bool killClient(
517  UT_WorkBuffer& errors,
518  int client_index,
519  bool restart);
520  bool resetClient(
521  UT_WorkBuffer& errors,
522  ClientInfo* client);
523  bool cleanupClients(
524  UT_WorkBuffer& errors,
525  ClientCleanupType cleanup_type,
526  bool stop_mq_server);
527 
528 private:
529  static constexpr int theMaxConcurrentStartup = 24;
530  static constexpr int theSleepTime = 10;
531  static constexpr int theMQSleepTime = 100;
532 
533  using PollingClient = UT_UniquePtr<PDGN::PDGN_PollingClientNNG>;
534  using ClientInfoArray = UT_Array<UT_UniquePtr<ClientInfo>>;
535 
536 private:
537  ClientInfoArray myPendingClients;
538  ClientInfoArray myActiveClients;
539  PDG_WorkItemIDSet myActiveLocks;
540 
541  UT_StringHolder myName;
542  UT_StringHolder myCommand;
543 
544  UT_StringHolder mySchedulerName;
545  UT_StringHolder mySchedulerContextName;
546 
547  UT_StringHolder myMqUrl;
548  UT_StringHolder myMqLogDir;
549 
550  UT_StringHolder myClientLogDir;
551 
552  UT_StringArray myEnvVarNames;
553  UT_StringArray myEnvVarValues;
554  UT_StringArray myExtraArguments;
555 
556  PollingClient myPollingClient;
557  UT_Thread* myPollingThread;
558  UT_Thread* myStartThread;
559 
560  PY_PyObject* myData;
561 
562  exint myMemoryLimit;
563 
564  pid_t myMqPid;
565 
566  SYS_AtomicInt<int> myPollingClientCount;
567 
568  int myConnectionTimeout;
569  int myMqLogLevel;
570  int myMqPort;
571  int myPoolSize;
572  int myPort;
573 
574  PDG_ServiceOwner myServiceOwner;
575  PDG_ServiceState myState;
576  PDG_ServiceLogType myClientLogType;
577 
578  PDG_ServiceResetType myMemoryResetType;
579 
580  bool myIsAutoStart;
581  bool myIsInternal;
582  bool myIsPersistent;
583  bool myHasErrors;
584 
585  UT_Lock myServiceLock;
586  mutable UT_Lock myClientLock;
587 };
588 
589 #endif
exint PDG_WorkItemID
Type defs for unique work item IDs.
void setState(PDG_ServiceState state)
Sets/gets the current state of the service.
Definition: PDG_Service.h:271
static const UT_StringHolder theDataVersion
Service data format version.
Definition: PDG_Service.h:46
A service client was successfully acquired.
Definition: PDG_Service.h:52
Service client array entry.
Definition: PDG_Service.h:69
PDG_WorkItemID myLock
Definition: PDG_Service.h:123
PDG_ServiceResetType
const UT_StringArray & envVarValues() const
Definition: PDG_Service.h:234
UT_StringHolder myName
The name of the service client.
Definition: PDG_Service.h:99
void setOwner(PDG_ServiceOwner owner)
Definition: PDG_Service.h:265
void setExtraArguments(const UT_StringArray &args)
Sets/gets the extra args array for the service.
Definition: PDG_Service.h:238
int mqPort() const
Definition: PDG_Service.h:199
void setName(const UT_StringHolder &name)
Definition: PDG_Service.h:146
#define PDG_API
Definition: PDG_API.h:23
exint myId
The process or job id for the client.
Definition: PDG_Service.h:112
int64 exint
Definition: SYS_Types.h:125
void setMqUrl(const UT_StringHolder &url)
Definition: PDG_Service.h:184
void setMemoryLimit(exint memory_limit)
Definition: PDG_Service.h:308
void setMqLogLevel(int log_level)
Definition: PDG_Service.h:191
The service lock is invalid – should never occur in practice.
Definition: PDG_Service.h:65
void setEnvVarNames(const UT_StringArray &env_var_names)
Definition: PDG_Service.h:224
bool hasErrors() const
Returns true if the service has errors when starting.
Definition: PDG_Service.h:166
bool isPersistent() const
Definition: PDG_Service.h:162
void setAutoStart(bool auto_start)
Definition: PDG_Service.h:171
const UT_StringHolder & schedulerName() const
Definition: PDG_Service.h:255
const UT_StringHolder & mqLogDir() const
Definition: PDG_Service.h:212
void setClientLogType(PDG_ServiceLogType log_type)
Sets how the service itself should log output.
Definition: PDG_Service.h:216
std::unique_ptr< T, Deleter > UT_UniquePtr
A smart pointer for unique ownership of dynamically allocated objects.
Definition: UT_UniquePtr.h:39
int poolSize() const
Definition: PDG_Service.h:287
void setConnectionTimeout(int ms)
Sets the service connection timeout in milliseconds.
Definition: PDG_Service.h:297
exint myTotalCooks
The total number of tasks the service has cooked.
Definition: PDG_Service.h:115
GLint GLint GLsizei GLint GLenum GLenum type
Definition: glcorearb.h:108
UT_StringHolder myAddress
The connection address.
Definition: PDG_Service.h:105
void setClientLogDir(const UT_StringHolder &log_dir)
Definition: PDG_Service.h:204
const UT_StringArray & envVarNames() const
Definition: PDG_Service.h:226
bool isAutoStart() const
Definition: PDG_Service.h:173
exint myPort
The connection port.
Definition: PDG_Service.h:109
void setEnvVarValues(const UT_StringArray &env_var_values)
Definition: PDG_Service.h:232
static const UT_StringHolder theEmptyString
A service client was successfully acquired and locked.
Definition: PDG_Service.h:55
PY_PyObject
int mqLogLevel() const
Definition: PDG_Service.h:193
PDG_ServiceResetWhen
When service clients should be reset.
UT_StringHolder myLogPath
The log path for client output.
Definition: PDG_Service.h:102
long long int64
Definition: SYS_Types.h:116
void setMqPort(int mq_port)
Sets/gets the port used by the MQ relay.
Definition: PDG_Service.h:197
ServiceAcquireResult
Enumeration of return codes from acquireClient.
Definition: PDG_Service.h:49
PDG_ServiceResetType memoryResetType() const
Definition: PDG_Service.h:313
GLuint const GLchar * name
Definition: glcorearb.h:786
bool isInternal() const
Definition: PDG_Service.h:153
UT_StringArray myCommandArgs
The array of command line args for the client.
Definition: PDG_Service.h:96
void setMemoryResetType(PDG_ServiceResetType memory_reset_type)
Sets the memory limit and reset type for the service.
Definition: PDG_Service.h:303
const UT_StringHolder & command() const
Definition: PDG_Service.h:280
PDGN::PDGN_PollingClientNNG * getPollingClient() const
Definition: PDG_Service.h:436
PDG_ServiceLogType
Enumeration of service log types.
All service workers are already busy.
Definition: PDG_Service.h:58
GLenum GLfloat param
Definition: glcorearb.h:104
void setPersistent(bool persistent)
Definition: PDG_Service.h:160
PDG_ServiceOwner owner() const
Definition: PDG_Service.h:267
void setCommand(const UT_StringHolder &command)
Definition: PDG_Service.h:278
const UT_StringArray & extraArguments() const
Definition: PDG_Service.h:240
const UT_StringHolder & mqUrl() const
Definition: PDG_Service.h:186
const UT_StringHolder & name() const
Definition: PDG_Service.h:148
const UT_StringHolder & schedulerContextName() const
Definition: PDG_Service.h:260
const UT_StringHolder & clientLogDir() const
Definition: PDG_Service.h:206
PDG_ServiceOwner
Enumeration of the different types of service owner.
PDG_ServiceStartResult
Enumeration of possible result values from starting a service.
PDG_ServiceState
Enumeration of the different states that a service can be in.
exint memoryLimit() const
Definition: PDG_Service.h:315
**If you just want to fire and args
Definition: thread.h:618
bool myIsActive
Set to true if the client is active for a job.
Definition: PDG_Service.h:129
int connectionTimeout() const
Definition: PDG_Service.h:299
int port() const
Definition: PDG_Service.h:293
bool myIsConnected
Set to true once the client has connected.
Definition: PDG_Service.h:126
bool hasPollingClient() const
Returns true if the service has an active polling client.
Definition: PDG_Service.h:431
void setMqLogDir(const UT_StringHolder &log_dir)
Sets/gets the directory that the MQ relay writes its logs to.
Definition: PDG_Service.h:210
void setPoolSize(int pool_size)
Definition: PDG_Service.h:285
PDG_ServiceState state() const
Definition: PDG_Service.h:273
state
Definition: core.h:2289
PDG_ServiceLogType clientLogType() const
Definition: PDG_Service.h:218
PY_PyObject * data()
Definition: PDG_Service.h:179
void setPort(int port)
Sets/gets the connection port for the service itself.
Definition: PDG_Service.h:291