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 
92  /// The array of command line args for the client
94 
95  /// The name of the service client
97 
98  /// The log path for client output
100 
101  /// The connection address
103 
104 
105  /// The connection port
107 
108  /// The process or job id for the client
110 
111  /// The total number of tasks the service has cooked
113 
114  /// The amount of memory in use by the process, as recorded by the
115  /// last task that cooked using the client
117 
118  /// The ID of the work item that has locked the service client, if
119  /// any
121 
122  /// Set to true once the client has connected
124 
125  /// Set to true if the client is active for a job
127  };
128 
129 public:
130 
131  /// Constructs a new service instance with a default pool size of 1, and
132  /// no connection information.
133  PDG_Service(
134  const PDG_BaseType* type,
135  const PDGT_ValueArgs& extra_args,
136  const UT_StringHolder& service_command,
137  bool internal_service);
138 
139  ~PDG_Service() override;
140 
141  /// Sets/gets the unique name for the service. The name of the service is
142  /// unique to the PDG_ServiceManager that created it.
144  { myName = name; }
145  const UT_StringHolder& name() const
146  { return myName; }
147 
148  /// Returns true if the service is internal to PDG. Internal services
149  /// cannot be directly managed by users.
150  bool isInternal() const
151  { return myIsInternal; }
152 
153  /// Sets/gets the persistent flag, which determines whether a service
154  /// should be persisted to the pdgservice JSON configuration file. A
155  /// service that isn't persistent will be lost when the Houdini session
156  /// is closed.
157  void setPersistent(bool persistent)
158  { myIsPersistent = persistent; }
159  bool isPersistent() const
160  { return myIsPersistent; }
161 
162  /// Returns true if the service has errors when starting
163  bool hasErrors() const
164  { return myHasErrors; }
165 
166  /// Sets/gets the autostart flag, which indicates that the service will
167  /// start automatically when work items need to use it.
168  void setAutoStart(bool auto_start)
169  { myIsAutoStart = auto_start; }
170  bool isAutoStart() const
171  { return myIsAutoStart; }
172 
173  /// Sets/gets an opaque Python data object that can be stored on the
174  /// service.
175  void setData(PY_PyObject* new_data);
177  { return myData; }
178 
179  /// Sets/gets the MQ url that the service should use to relay messages
180  /// between service clients and the PDG graph
181  void setMqUrl(const UT_StringHolder& url)
182  { myMqUrl = url; }
183  const UT_StringHolder& mqUrl() const
184  { return myMqUrl; }
185 
186  /// Sets/gets the log level for the MQ process that relays messages
187  /// between clients and the PDG graph
188  void setMqLogLevel(int log_level)
189  { myMqLogLevel = log_level; }
190  int mqLogLevel() const
191  { return myMqLogLevel; }
192 
193  /// Sets/gets the port used by the MQ relay.
194  void setMqPort(int mq_port)
195  { myMqPort = mq_port; }
196  int mqPort() const
197  { return myMqPort; }
198 
199  /// Sets/gets the directory that service clients should write their log
200  /// files to.
201  void setClientLogDir(const UT_StringHolder& log_dir)
202  { myClientLogDir = log_dir; }
204  { return myClientLogDir; }
205 
206  /// Sets/gets the directory that the MQ relay writes its logs to.
207  void setMqLogDir(const UT_StringHolder& log_dir)
208  { myMqLogDir = log_dir; }
209  const UT_StringHolder& mqLogDir() const
210  { return myMqLogDir; }
211 
212  /// Sets how the service itself should log output
214  { myClientLogType = log_type; }
216  { return myClientLogType; }
217 
218  /// Sets/gets the names for the environment variables to be set in
219  /// this job's environment. This only applies if the service does not
220  /// have a scheduler.
221  void setEnvVarNames(const UT_StringArray& env_var_names)
222  { myEnvVarNames = env_var_names; }
224  { return myEnvVarNames; }
225 
226  /// Sets/gets the values for the environment variables to be set in
227  /// this job's environment. This only applies if the service does not
228  /// have a scheduler.
229  void setEnvVarValues(const UT_StringArray& env_var_values)
230  { myEnvVarValues = env_var_values; }
232  { return myEnvVarValues; }
233 
234  /// Sets/gets the extra args array for the service
236  { myExtraArguments = args; }
238  { return myExtraArguments; }
239 
240  /// For scheduler services, sets the name of the scheduler and graph
241  /// that created the service.
242  void setScheduler(
243  const UT_StringHolder& name,
244  const UT_StringHolder& context_name);
245 
246  /// Clears the scheduler information associated with a scheduler
247  /// service
248  void clearScheduler();
249 
250  /// Returns the name of the scheduler associated with the service, if
251  /// it's a scheduler service
253  { return mySchedulerName; }
254 
255  /// Returns the name of the graph that owns the scheduler that created
256  /// the service, if it's a scheduler service
258  { return mySchedulerContextName; }
259 
260  /// Sets/gets the service owner type -- either a session service or a
261  /// scheduler service
263  { myServiceOwner = owner; }
265  { return myServiceOwner; }
266 
267  /// Sets/gets the current state of the service
269  { myState = state; }
271  { return myState; }
272 
273  /// Sets/gets the command line string that should be used to start clients
274  /// running in the service pool
275  void setCommand(const UT_StringHolder& command)
276  { myCommand = command; }
277  const UT_StringHolder& command() const
278  { return myCommand; }
279 
280  /// Sets/gets the pool size for the service, which determines the number
281  /// of concurrent client processes that service executes
282  void setPoolSize(int pool_size)
283  { myPoolSize = pool_size; }
284  int poolSize() const
285  { return myPoolSize; }
286 
287  /// Sets/gets the connection port for the service itself
288  void setPort(int port)
289  { myPort = port; }
290  int port() const
291  { return myPort; }
292 
293  /// Sets the service connection timeout in milliseconds
294  void setConnectionTimeout(int ms)
295  { myConnectionTimeout = ms; }
296  int connectionTimeout() const
297  { return myConnectionTimeout; }
298 
299  /// Sets the memory limit and reset type for the service
301  PDG_ServiceResetType memory_reset_type)
302  {
303  myMemoryResetType = memory_reset_type;
304  }
306  exint memory_limit)
307  {
308  myMemoryLimit = memory_limit;
309  }
311  { return myMemoryResetType; }
313  { return myMemoryLimit; }
314 
315  /// Returns true if the service is start or is already running
316  bool isStartingOrRunning() const;
317 
318  /// Returns true if the service is stopping, or has already stopped
319  bool isStoppingOrStopped() const;
320 
321  /// Queries and returns the scheduler associated with the service, if the
322  /// service is a scheduler service
323  PDG_Scheduler* serviceScheduler(UT_WorkBuffer& errors) const;
324 
325 
326  /// Queries the list of all active service client names
327  UT_StringArray clientNames() const;
328 
329  /// Queries the name of a particular service client, using its client
330  /// number
331  UT_StringHolder clientName(int client_num) const;
332 
333  /// Returns the service client info for a particular client
334  ClientInfo* client(const UT_StringHolder& name);
335 
336  /// Adds a pending service client, which can be waiting on using
337  /// waitForClients
338  ClientInfo* addPendingClient(
339  const UT_StringHolder& server_address,
340  int server_port,
341  int client_num);
342 
343 
344  /// Stats a service pool. If background is true the service processes are
345  /// start asynchronously, and control immediately returns after calling
346  /// this function. It's up to the caller to ensure that the service has
347  /// started before using it. Returns either success, failure, or already-
348  /// running.
349  PDG_ServiceStartResult startService(
350  UT_WorkBuffer& errors,
351  bool background);
352 
353  /// Resets a specific service client, or all clients if empty string is
354  /// passed in as the client_name
355  bool resetClient(
356  UT_WorkBuffer& errors,
357  const UT_StringHolder& client_name =
359 
360  /// Restarts a service client. If client_name is empty string all
361  /// clients are restarted.
362  bool restartClient(
363  UT_WorkBuffer& errors,
364  const UT_StringHolder& client_name);
365 
366  /// Stops a service client and kills the process associated with it.
367  /// The client can be started again at a later point using restartClient.
368  /// If client_name is empty string all clients are stoppped.
369  bool stopClient(
370  UT_WorkBuffer& errors,
371  const UT_StringHolder& client_name);
372 
373  /// Stops the service if it's running, and returns a boolean to indiate
374  /// the status.
375  bool stopService(
376  UT_WorkBuffer& errors,
377  bool ignore_stopped);
378 
379  /// Cleans up the clients in the service. This method is public so that
380  /// schedulers can call it on services they manage.
381  bool cleanupService(
382  UT_WorkBuffer& errors,
383  bool stop_mq_server,
384  bool wait_for_clients);
385 
386  /// Submits a work item to a service client asynchronously, and returns
387  /// the pending message handle for the job.
388  PDGN::PDGN_Message* executeWorkItem(
389  UT_WorkBuffer& errors,
390  const UT_StringHolder& client_name,
391  const PDG_WorkItem* work_item);
392 
393  /// Submits a work item to a service client asychronously, and returns
394  /// the pending messae handle for the job. This variant of the method
395  /// allows the caller to supply a custom script that will run instead of
396  /// the standard job script or script data associated with the work item.
397  PDGN::PDGN_Message* executeWorkItem(
398  UT_WorkBuffer& errors,
399  const UT_StringHolder& client_name,
400  const PDG_WorkItem* work_item,
401  const UT_WorkBuffer& script_buffer);
402 
403  /// Starts a background thread that polls the ready listener until all
404  /// service clients have connected
405  void startPollingClient();
406 
407  /// This will force stop the ready listener. If you want to wait for it to
408  /// complete, you should call waitForClients() instead.
409  void stopPollingClient();
410 
411  /// Returns the name of the polling client, if one exists
412  const UT_StringHolder& pollingClientName() const;
413 
414  /// Returns true if the service has an active polling client
415  bool hasPollingClient() const
416  { return (myPollingClient != nullptr); }
417 
418  // Returns a pointer to the polling client, or nullptr if none exists.
419  PDGN::PDGN_PollingClientNNG*
421  { return myPollingClient.get(); }
422 
423  /// Waits for all pending service clients to connect, and then terminates
424  /// the ready listener
425  void waitForClients();
426 
427  /// Increments the number of actively starting client
428  void incrementStartingClientsCount();
429 
430  /// Returns the command for the service client with the specified client
431  /// number, as a string.
432  UT_StringHolder getCommand(
433  const char* server_address,
434  int server_port,
435  int client_num) const;
436 
437  /// Returns the command for the service client with the specified client
438  /// number, as an array of arguments
439  void getCommand(
440  UT_StringArray& command_tokens,
441  const char* server_address,
442  int server_port,
443  int client_num) const;
444 
445  /// Pings the specified client, and returns true if the client was
446  /// reachable
447  bool ping(int client_num, UT_WorkBuffer& errors) const;
448 
449  /// Acquires a client, which reserves it for the caller
450  ServiceAcquireResult acquireClient(
451  UT_StringHolder& client_name,
452  PDG_WorkItemID item_lock);
453 
454  /// Releases a client that was previously acquired, but does not unlock it
455  bool releaseClient(
456  UT_WorkBuffer& errors,
457  const UT_StringHolder& client_name,
458  PDG_ServiceResetWhen reset_when,
459  PDG_ServiceResetType reset_type,
460  int64 memory_usage);
461 
462  /// Unlocks a service client
463  bool unlockClient(
464  PDG_WorkItemID item_lock,
465  PDG_ServiceResetType reset_type,
466  UT_WorkBuffer& errors);
467 
468 private:
469  static void* runSpawnSessionService(void* param);
470  static void* runPollingThread(void* param);
471 
472  bool getClientNameFromMessage(
473  PDGN::PDGN_Message* msg,
474  UT_StringHolder& client_name);
475 
476  bool startSessionService(
477  UT_WorkBuffer& errors,
478  bool background);
479  bool spawnSessionServiceClients();
480  void pollClients();
481 
482  bool stopSessionService(UT_WorkBuffer& errors);
483  bool stopClient(
484  UT_WorkBuffer& errors,
485  int client_index,
486  bool restart);
487  bool resetClient(
488  UT_WorkBuffer& errors,
489  ClientInfo* client);
490  bool cleanupClients(
491  UT_WorkBuffer& errors,
492  bool stop_mq_server,
493  bool wait_for_clients);
494 
495 private:
496  static constexpr int theMaxConcurrentStartup = 24;
497  static constexpr int theSleepTime = 10;
498 
499  using PollingClient = UT_UniquePtr<PDGN::PDGN_PollingClientNNG>;
500  using ClientInfoArray = UT_Array<UT_UniquePtr<ClientInfo>>;
501 
502 private:
503  ClientInfoArray myPendingClients;
504  ClientInfoArray myActiveClients;
505  PDG_WorkItemIDSet myActiveLocks;
506 
507  UT_StringHolder myName;
508  UT_StringHolder myCommand;
509 
510  UT_StringHolder mySchedulerName;
511  UT_StringHolder mySchedulerContextName;
512 
513  UT_StringHolder myMqUrl;
514  UT_StringHolder myMqLogDir;
515 
516  UT_StringHolder myClientLogDir;
517 
518  UT_StringArray myEnvVarNames;
519  UT_StringArray myEnvVarValues;
520  UT_StringArray myExtraArguments;
521 
522  PollingClient myPollingClient;
523  UT_Thread* myPollingThread;
524  UT_Thread* myStartThread;
525 
526  PY_PyObject* myData;
527 
528  exint myMemoryLimit;
529 
530  pid_t myMqPid;
531 
532  SYS_AtomicInt<int> myPollingClientCount;
533 
534  int myConnectionTimeout;
535  int myMqLogLevel;
536  int myMqPort;
537  int myPoolSize;
538  int myPort;
539 
540  PDG_ServiceOwner myServiceOwner;
541  PDG_ServiceState myState;
542  PDG_ServiceLogType myClientLogType;
543 
544  PDG_ServiceResetType myMemoryResetType;
545 
546  bool myIsAutoStart;
547  bool myIsInternal;
548  bool myIsPersistent;
549  bool myHasErrors;
550 
551  UT_Lock myServiceLock;
552  mutable UT_Lock myClientLock;
553 };
554 
555 #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:268
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:120
PDG_ServiceResetType
const UT_StringArray & envVarValues() const
Definition: PDG_Service.h:231
UT_StringHolder myName
The name of the service client.
Definition: PDG_Service.h:96
void setOwner(PDG_ServiceOwner owner)
Definition: PDG_Service.h:262
void setExtraArguments(const UT_StringArray &args)
Sets/gets the extra args array for the service.
Definition: PDG_Service.h:235
int mqPort() const
Definition: PDG_Service.h:196
void setName(const UT_StringHolder &name)
Definition: PDG_Service.h:143
#define PDG_API
Definition: PDG_API.h:23
exint myId
The process or job id for the client.
Definition: PDG_Service.h:109
int64 exint
Definition: SYS_Types.h:125
void setMqUrl(const UT_StringHolder &url)
Definition: PDG_Service.h:181
void setMemoryLimit(exint memory_limit)
Definition: PDG_Service.h:305
void setMqLogLevel(int log_level)
Definition: PDG_Service.h:188
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:221
bool hasErrors() const
Returns true if the service has errors when starting.
Definition: PDG_Service.h:163
bool isPersistent() const
Definition: PDG_Service.h:159
void setAutoStart(bool auto_start)
Definition: PDG_Service.h:168
const UT_StringHolder & schedulerName() const
Definition: PDG_Service.h:252
const UT_StringHolder & mqLogDir() const
Definition: PDG_Service.h:209
void setClientLogType(PDG_ServiceLogType log_type)
Sets how the service itself should log output.
Definition: PDG_Service.h:213
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:284
void setConnectionTimeout(int ms)
Sets the service connection timeout in milliseconds.
Definition: PDG_Service.h:294
exint myTotalCooks
The total number of tasks the service has cooked.
Definition: PDG_Service.h:112
UT_StringHolder myAddress
The connection address.
Definition: PDG_Service.h:102
void setClientLogDir(const UT_StringHolder &log_dir)
Definition: PDG_Service.h:201
const UT_StringArray & envVarNames() const
Definition: PDG_Service.h:223
bool isAutoStart() const
Definition: PDG_Service.h:170
exint myPort
The connection port.
Definition: PDG_Service.h:106
void setEnvVarValues(const UT_StringArray &env_var_values)
Definition: PDG_Service.h:229
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:190
PDG_ServiceResetWhen
When service clients should be reset.
UT_StringHolder myLogPath
The log path for client output.
Definition: PDG_Service.h:99
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:194
ServiceAcquireResult
Enumeration of return codes from acquireClient.
Definition: PDG_Service.h:49
PDG_ServiceResetType memoryResetType() const
Definition: PDG_Service.h:310
GLuint const GLchar * name
Definition: glcorearb.h:786
bool isInternal() const
Definition: PDG_Service.h:150
UT_StringArray myCommandArgs
The array of command line args for the client.
Definition: PDG_Service.h:93
void setMemoryResetType(PDG_ServiceResetType memory_reset_type)
Sets the memory limit and reset type for the service.
Definition: PDG_Service.h:300
const UT_StringHolder & command() const
Definition: PDG_Service.h:277
PDGN::PDGN_PollingClientNNG * getPollingClient() const
Definition: PDG_Service.h:420
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:157
PDG_ServiceOwner owner() const
Definition: PDG_Service.h:264
void setCommand(const UT_StringHolder &command)
Definition: PDG_Service.h:275
const UT_StringArray & extraArguments() const
Definition: PDG_Service.h:237
const UT_StringHolder & mqUrl() const
Definition: PDG_Service.h:183
const UT_StringHolder & name() const
Definition: PDG_Service.h:145
const UT_StringHolder & schedulerContextName() const
Definition: PDG_Service.h:257
const UT_StringHolder & clientLogDir() const
Definition: PDG_Service.h:203
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:312
**If you just want to fire and args
Definition: thread.h:609
bool myIsActive
Set to true if the client is active for a job.
Definition: PDG_Service.h:126
int connectionTimeout() const
Definition: PDG_Service.h:296
int port() const
Definition: PDG_Service.h:290
bool myIsConnected
Set to true once the client has connected.
Definition: PDG_Service.h:123
bool hasPollingClient() const
Returns true if the service has an active polling client.
Definition: PDG_Service.h:415
void setMqLogDir(const UT_StringHolder &log_dir)
Sets/gets the directory that the MQ relay writes its logs to.
Definition: PDG_Service.h:207
void setPoolSize(int pool_size)
Definition: PDG_Service.h:282
type
Definition: core.h:1059
PDG_ServiceState state() const
Definition: PDG_Service.h:270
PDG_ServiceLogType clientLogType() const
Definition: PDG_Service.h:215
PY_PyObject * data()
Definition: PDG_Service.h:176
void setPort(int port)
Sets/gets the connection port for the service itself.
Definition: PDG_Service.h:288