rda-python-common 1.0.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of rda-python-common might be problematic. Click here for more details.

@@ -0,0 +1,639 @@
1
+ #
2
+ ###############################################################################
3
+ #
4
+ # Title : PgLock.py
5
+ # Author : Zaihua Ji, zji@ucar.edu
6
+ # Date : 08/118/2020
7
+ # Purpose : python library module for functions to lock RDADB records
8
+ #
9
+ # Work File : $DSSHOME/lib/python/PgLock.py
10
+ # Github : https://github.com/NCAR/rda-shared-libraries.git
11
+ #
12
+ ###############################################################################
13
+ #
14
+ import re
15
+ import time
16
+ import PgLOG
17
+ import PgSIG
18
+ import PgUtil
19
+ import PgFile
20
+ import PgDBI
21
+
22
+ DOLOCKS = {-2 : 'Force Unlock', -1 : 'Unlock', 0 : 'Unlock', 1 : 'Relock', 2 : 'Force Relock'}
23
+
24
+ def end_db_transaction(idx):
25
+
26
+ if idx > 0:
27
+ PgDBI.endtran()
28
+ else:
29
+ PgDBI.aborttran()
30
+ return idx
31
+
32
+ #
33
+ # check and return running process status: 1-running/uncheckable,0-stopped
34
+ #
35
+ def check_process_running_status(host, pid, dolock, lmsg, logact):
36
+
37
+ if not PgFile.local_host_action(host, DOLOCKS[dolock], lmsg, logact): return 1
38
+ stat = PgSIG.check_host_pid(host, pid)
39
+ if stat > 0:
40
+ if logact: PgLOG.pglog("{}: Cannot {}".format(lmsg, DOLOCKS[dolock]), logact)
41
+ return 1
42
+ if stat < 0 and dolock > -2 and dolock < 2:
43
+ if logact: PgLOG.pglog("{}: Fail checking lock info to {}".format(lmsg, DOLOCKS[dolock]), logact)
44
+ return 1
45
+ return 0
46
+
47
+ #
48
+ # lock/unlock dscheck record
49
+ #
50
+ # lock if dolock > 0, unlock if <= 0, skip for locked on different host if 0 or 1
51
+ # force unlock if < -1 or force lock if 2
52
+ #
53
+ def lock_dscheck(cidx, dolock, logact = 0):
54
+
55
+ if not cidx: return 0
56
+ if logact:
57
+ logerr = logact|PgLOG.ERRLOG
58
+ logout = logact&(~PgLOG.EXITLG)
59
+ else:
60
+ logerr = PgLOG.LOGERR
61
+ logout = PgLOG.LOGWRN if dolock > 1 or dolock < 0 else 0
62
+ table = "dscheck"
63
+ cnd = "cindex = {}".format(cidx)
64
+ fields = "command, pid, lockhost, lockcmd"
65
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr)
66
+ if not pgrec: return 0 # dscheck is gone or db error
67
+
68
+ pid = pgrec['pid']
69
+ host = pgrec['lockhost']
70
+ lockcmd = pgrec['lockcmd']
71
+ (chost, cpid) = PgLOG.current_process_info()
72
+ clockcmd = PgLOG.get_command()
73
+
74
+ if pid == 0 and dolock <= 0: return cidx # no need unlock
75
+ lckpid = -pid if pid > 0 and pid == cpid and not PgUtil.pgcmp(host, chost, 1) else pid
76
+ if dolock > 0 and lckpid < 0: return cidx # no need lock again
77
+
78
+ cinfo = "{}-{}-Chk{}({})".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.current_datetime(), cidx, pgrec['command'])
79
+ if lckpid > 0 and (clockcmd == "dscheck" or lockcmd != "dscheck"):
80
+ lmsg = "{} Locked by {}/{}/{}".format(cinfo, pid, host, lockcmd)
81
+ if check_process_running_status(host, pid, dolock, lmsg, logout): return -cidx
82
+
83
+ record = {}
84
+ if dolock > 0:
85
+ if pid != cpid: record['pid'] = cpid
86
+ if host != chost: record['lockhost'] = chost
87
+ if lockcmd != clockcmd: record['lockcmd'] = clockcmd
88
+ else:
89
+ if pid: record['pid'] = 0
90
+ if not record: return cidx
91
+
92
+ lkrec = PgDBI.pgget(table, fields, cnd, logerr|PgLOG.DOLOCK)
93
+ if not lkrec: return end_db_transaction(0) # dscheck is gone or db error
94
+
95
+ if (not lkrec['pid'] or
96
+ lkrec['pid'] == pid and PgUtil.pgcmp(lkrec['lockhost'], host, 1) == 0 or
97
+ lkrec['pid'] == cpid and PgUtil.pgcmp(lkrec['lockhost'], chost, 1) == 0):
98
+ if not PgDBI.pgupdt(table, record, cnd, logerr):
99
+ if logout: PgLOG.pglog(cinfo + ": Error update lock", logout)
100
+ cidx = -cidx
101
+ else:
102
+ if logout: PgLOG.pglog("{}: Relocked {}/{}".format(cinfo, lkrec['pid'], lkrec['lockhost']), logout)
103
+ cidx = -cidx
104
+
105
+ return end_db_transaction(cidx)
106
+
107
+ #
108
+ # lock dscheck record for given cidx, pid and host
109
+ #
110
+ def lock_host_dscheck(cidx, pid, host, logact = 0):
111
+
112
+ if not (cidx and pid): return 0
113
+ if logact:
114
+ logerr = logact|PgLOG.ERRLOG
115
+ logout = logact&(~PgLOG.EXITLG)
116
+ else:
117
+ logerr = PgLOG.LOGERR
118
+ logout = 0
119
+ table = "dscheck"
120
+ cnd = "cindex = {}".format(cidx)
121
+ fields = "command, pid, lockhost, lockcmd"
122
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr)
123
+ if not pgrec: return 0 # dscheck is gone or db error
124
+ (chost, cpid) = PgLOG.current_process_info()
125
+
126
+ cinfo = "{}-{}-Chk{}({})".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.current_datetime(), cidx, pgrec['command'])
127
+ if pgrec['pid']:
128
+ if pid == pgrec['pid'] and PgUtil.pgcmp(pgrec['lockhost'], host, 1) == 0:
129
+ return -cidx # locked by the real process already
130
+ elif cpid != pgrec['pid'] or PgUtil.pgcmp(pgrec['lockhost'], chost, 1):
131
+ if logout:
132
+ lmsg = "{} Locked by {}/{}/{}".format(cinfo, pid, host, pgrec['lockcmd'])
133
+ PgLOG.pglog(lmsg +": Cannot Lock", logout)
134
+ return -cidx # locked by other process
135
+
136
+ record = {}
137
+ record['pid'] = pid
138
+ record['lockhost'] = host
139
+ record['lockcmd'] = PgLOG.get_command(pgrec['command'])
140
+
141
+ lkrec = PgDBI.pgget(table, fields, cnd, logerr|PgLOG.DOLOCK)
142
+ if not lkrec: return end_db_transaction(0)
143
+
144
+ if (not lkrec['pid'] or
145
+ lkrec['pid'] == pid and PgUtil.pgcmp(lkrec['lockhost'], host, 1) == 0 or
146
+ lkrec['pid'] == cpid and PgUtil.pgcmp(lkrec['lockhost'], chost, 1) == 0):
147
+ if not PgDBI.pgupdt(table, record, cnd, logerr):
148
+ if logout: PgLOG.pglog(cinfo + ": Error update lock", logout)
149
+ cidx = -cidx
150
+ else:
151
+ if logout: PgLOG.pglog("{}: Relocked {}/{}".format(cinfo, lkrec['pid'], lkrec['lockhost']), logout)
152
+ cidx = -cidx
153
+
154
+ return end_db_transaction(cidx)
155
+
156
+ #
157
+ # lock/unlock data request record
158
+ #
159
+ # lock if dolock > 0, unlock if <= 0, skip for locked on different host if 0 or 1
160
+ # force unlock if < -1 or 2
161
+ #
162
+ def lock_request(ridx, dolock, logact = 0):
163
+
164
+ if not ridx: return 0
165
+ if logact:
166
+ logerr = logact|PgLOG.ERRLOG
167
+ logout = logact&(~PgLOG.EXITLG)
168
+ else:
169
+ logerr = PgLOG.LOGERR
170
+ logout = PgLOG.LOGWRN if dolock > 1 or dolock < 0 else 0
171
+ table = "dsrqst"
172
+ cnd = "rindex = {}".format(ridx)
173
+ fields = "pid, lockhost"
174
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr)
175
+ if not pgrec: return 0 # request is gone or db error
176
+
177
+ pid = pgrec['pid']
178
+ host = pgrec['lockhost']
179
+ (chost, cpid) = PgLOG.current_process_info()
180
+
181
+ if pid == 0 and dolock <= 0: return ridx # no need unlock
182
+ lckpid = -pid if pid > 0 and pid == cpid and not PgUtil.pgcmp(host, chost, 1) else pid
183
+ if dolock > 0 and lckpid < 0: return ridx # no need lock again
184
+
185
+ rinfo = "{}-{}-Rqst{}".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.current_datetime(), ridx)
186
+ if lckpid > 0:
187
+ lmsg = "{} Locked by {}/{}".format(rinfo, pid, host)
188
+ if check_process_running_status(host, pid, dolock, lmsg, logout): return -ridx
189
+
190
+ record = {}
191
+ if dolock > 0:
192
+ if pid != cpid: record['pid'] = cpid
193
+ if host != chost: record['lockhost'] = chost
194
+ if record: record['locktime'] = int(time.time())
195
+ else:
196
+ if pid: record['pid'] = 0
197
+ if host: record['lockhost'] = ""
198
+ if not record: return ridx
199
+
200
+ lkrec = PgDBI.pgget(table, fields, cnd, logerr|PgLOG.DOLOCK)
201
+ if not lkrec: return end_db_transaction(0) # request is gone or db error
202
+
203
+ if (not lkrec['pid'] or
204
+ lkrec['pid'] == pid and PgUtil.pgcmp(lkrec['lockhost'], host, 1) == 0 or
205
+ lkrec['pid'] == cpid and PgUtil.pgcmp(lkrec['lockhost'], chost, 1) == 0):
206
+ if not PgDBI.pgupdt(table, record, cnd, logerr):
207
+ if logout: PgLOG.pglog(rinfo + ": Error update lock", logout)
208
+ ridx = -ridx
209
+ else:
210
+ if logout: PgLOG.pglog("{}: Relocked {}/{}".format(rinfo, lkrec['pid'], lkrec['lockhost']), logout)
211
+ ridx = -ridx
212
+
213
+ return end_db_transaction(ridx)
214
+
215
+ #
216
+ # lock dsrqst record for given cidx, pid and host
217
+ #
218
+ def lock_host_request(ridx, pid, host, logact = 0):
219
+
220
+ if not (ridx and pid): return 0
221
+ if logact:
222
+ logerr = logact|PgLOG.ERRLOG
223
+ logout = logact&(~PgLOG.EXITLG)
224
+ else:
225
+ logerr = PgLOG.LOGERR
226
+ logout = 0
227
+ table = "dsrqst"
228
+ cnd = "rindex = {}".format(ridx)
229
+ fields = "pid, lockhost"
230
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr)
231
+ if not pgrec: return 0 # dscheck is gone or db error
232
+
233
+ rinfo = "{}-{}-Rqst{}".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.current_datetime(), ridx)
234
+ if pgrec['pid']:
235
+ if pid == pgrec['pid'] and PgUtil.pgcmp(pgrec['lockhost'], host, 1) == 0: return ridx
236
+ if logout:
237
+ lmsg = "{} Locked by {}/{}".format(rinfo, pid, host)
238
+ PgLOG.pglog(lmsg +": Cannot Lock", logout)
239
+ return -ridx
240
+ record = {}
241
+ record['pid'] = pid
242
+ record['lockhost'] = host
243
+ record['locktime'] = int(time.time())
244
+
245
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr|PgLOG.DOLOCK)
246
+ if not pgrec: return end_db_transaction(0)
247
+
248
+ if not pgrec['pid'] or pid == pgrec['pid'] and PgUtil.pgcmp(pgrec['lockhost'], host, 1) == 0:
249
+ if not PgDBI.pgupdt(table, record, cnd, logerr):
250
+ if logout: PgLOG.pglog(rinfo + ": Error update lock", logout)
251
+ ridx = -ridx
252
+ else:
253
+ if logout: PgLOG.pglog("{}: Relocked {}/{}".format(rinfo, pgrec['pid'], pgrec['lockhost']), logout)
254
+ ridx = -ridx
255
+
256
+ return end_db_transaction(ridx)
257
+
258
+ #
259
+ # lock/unlock dataset update record
260
+ #
261
+ # lock if dolock > 0, unlock if <= 0, skip for locked on different host if 0 or 1
262
+ # force unlock if < -1 or 2
263
+ #
264
+ def lock_update(lidx, linfo, dolock, logact = 0):
265
+
266
+ if not lidx: return 0
267
+ if logact:
268
+ logerr = logact|PgLOG.ERRLOG
269
+ logout = logact&(~PgLOG.EXITLG)
270
+ else:
271
+ logerr = PgLOG.LOGERR
272
+ logout = PgLOG.LOGWRN if dolock > 1 or dolock < 0 else 0
273
+ table = "dlupdt"
274
+ cnd = "lindex = {}".format(lidx)
275
+ fields = "pid, hostname"
276
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr)
277
+ if not pgrec: return 0 # update record is deleted
278
+
279
+ pid = pgrec['pid']
280
+ host = pgrec['hostname']
281
+ (chost, cpid) = PgLOG.current_process_info()
282
+
283
+ if pid == 0 and dolock <= 0: return lidx # no need unlock
284
+ lckpid = -pid if pid > 0 and pid == cpid and not PgUtil.pgcmp(host, chost, 1) else pid
285
+ if dolock > 0 and lckpid < 0: return lidx # no need lock again
286
+
287
+ if not linfo: linfo = "{}-{}-Updt{}".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.current_datetime(), lidx)
288
+ if lckpid > 0:
289
+ lmsg = "{} Locked by {}/{}".format(linfo, pid, host)
290
+ if check_process_running_status(host, pid, dolock, lmsg, logout): return -lidx
291
+
292
+ record = {}
293
+ if dolock > 0:
294
+ if pid != cpid: record['pid'] = cpid
295
+ if host != chost: record['hostname'] = chost
296
+ if record: record['locktime'] = int(time.time())
297
+ else:
298
+ if pid: record['pid'] = 0
299
+ if host: record['hostname'] = ''
300
+ if not record: return lidx
301
+
302
+ lkrec = PgDBI.pgget(table, fields, cnd, logerr|PgLOG.DOLOCK)
303
+ if not lkrec: return end_db_transaction(0) # update record is deleted
304
+
305
+ if not lkrec['pid'] or lkrec['pid'] == pid and PgUtil.pgcmp(lkrec['hostname'], host, 1) == 0:
306
+ if not PgDBI.pgupdt(table, record, cnd, logerr):
307
+ if logout: PgLOG.pglog(linfo + ": Error update lock", logout)
308
+ lidx = -lidx
309
+ else:
310
+ if logout: PgLOG.pglog("{}: Relocked {}/{}".format(linfo, lkrec['pid'], lkrec['hostname']), logout)
311
+ lidx = -lidx
312
+
313
+ return end_db_transaction(lidx)
314
+
315
+ #
316
+ # lock/unlock dataset update control record
317
+ #
318
+ # lock if dolock > 0, unlock if <= 0, skip for locked on different host if 0 or 1,
319
+ # unlock dead process if < -1 or 2, force unlock if -2
320
+ #
321
+ def lock_update_control(cidx, dolock, logact = 0):
322
+
323
+ if not cidx: return 0
324
+ if logact:
325
+ logerr = logact|PgLOG.ERRLOG
326
+ logout = logact&(~PgLOG.EXITLG)
327
+ else:
328
+ logerr = PgLOG.LOGERR
329
+ logout = PgLOG.LOGWRN if dolock > 1 or dolock < 0 else 0
330
+ table = "dcupdt"
331
+ cnd = "cindex = {}".format(cidx)
332
+ fields = "pid, lockhost"
333
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr)
334
+ if not pgrec: return 0 # update control record is deleted
335
+
336
+ pid = pgrec['pid']
337
+ host = pgrec['lockhost']
338
+ (chost, cpid) = PgLOG.current_process_info()
339
+
340
+ if pid == 0 and dolock <= 0: return cidx # no need unlock
341
+ lckpid = -pid if pid > 0 and pid == cpid and not PgUtil.pgcmp(host, chost, 1) else pid
342
+ if dolock > 0 and lckpid < 0: return cidx # no need lock again
343
+
344
+ cinfo = "{}-{}-UC{}".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.current_datetime(), cidx)
345
+ if lckpid > 0:
346
+ lmsg = "{} Locked by {}/{}".format(cinfo, pid, host)
347
+ if check_process_running_status(host, pid, dolock, lmsg, logout): return -cidx
348
+
349
+ record = {}
350
+ if dolock > 0:
351
+ if pid != cpid: record['pid'] = cpid
352
+ if host != chost: record['lockhost'] = chost
353
+ if record: record['chktime'] = int(time.time())
354
+ else:
355
+ if pid: record['pid'] = 0
356
+ if host: record['lockhost'] = ''
357
+ if not record: return cidx
358
+
359
+ lkrec = PgDBI.pgget(table, fields, cnd, logerr|PgLOG.DOLOCK)
360
+ if not lkrec: return end_db_transaction(0) # update control record is deleted
361
+
362
+ if (not lkrec['pid'] or
363
+ lkrec['pid'] == pid and PgUtil.pgcmp(lkrec['lockhost'], host, 1) == 0 or
364
+ lkrec['pid'] == cpid and PgUtil.pgcmp(lkrec['lockhost'], chost, 1) == 0):
365
+ if not PgDBI.pgupdt(table, record, cnd, logerr):
366
+ if logout: PgLOG.pglog(cinfo + ": Error update lock", logout)
367
+ cidx = -cidx
368
+ else:
369
+ if logout: PgLOG.pglog("{}: Relocked {}/{}".format(cinfo, lkrec['pid'], lkrec['lockhost']), logout)
370
+ cidx = -cidx
371
+
372
+ return end_db_transaction(cidx)
373
+
374
+ #
375
+ # lock dscheck record for given cidx, pid and host
376
+ #
377
+ def lock_host_update_control(cidx, pid, host, logact = 0):
378
+
379
+ if not (cidx and pid): return 0
380
+ if logact:
381
+ logerr = logact|PgLOG.ERRLOG
382
+ logout = logact&(~PgLOG.EXITLG)
383
+ else:
384
+ logerr = PgLOG.LOGERR
385
+ logout = 0
386
+ table = "dcupdt"
387
+ cnd = "cindex = {}".format(cidx)
388
+ fields = "pid, lockhost"
389
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr)
390
+ if not pgrec: return 0 # dscheck is gone or db error
391
+
392
+ cinfo = "{}-{}-UC{}".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.current_datetime(), cidx)
393
+ if pgrec['pid']:
394
+ if pid == pgrec['pid'] and PgUtil.pgcmp(pgrec['lockhost'], host, 1) == 0: return cidx
395
+ if logout:
396
+ lmsg = "{} Locked by {}/{}".format(cinfo, pid, host)
397
+ PgLOG.pglog(lmsg +": Cannot Lock", logout)
398
+ return -cidx
399
+
400
+ record = {}
401
+ record['pid'] = pid
402
+ record['lockhost'] = host
403
+ record['chktime'] = int(time.time())
404
+
405
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr|PgLOG.DOLOCK)
406
+ if not pgrec: return end_db_transaction(0)
407
+
408
+ if not pgrec['pid'] or pid == pgrec['pid'] and PgUtil.pgcmp(pgrec['lockhost'], host, 1) == 0:
409
+ if not PgDBI.pgupdt(table, record, cnd, logerr):
410
+ if logout: PgLOG.pglog(cinfo + ": Error update lock", logout)
411
+ cidx = -cidx
412
+ else:
413
+ if logout: PgLOG.pglog("{}: Relocked {}/{}".format(cinfo, pgrec['pid'], pgrec['lockhost']), logout)
414
+ cidx = -cidx
415
+
416
+ return end_db_transaction(cidx)
417
+
418
+ #
419
+ # return lock information of a locked process
420
+ #
421
+ def lock_process_info(pid, lockhost, runhost = None, pcnt = 0):
422
+
423
+ retstr = " {}<{}".format(lockhost, pid)
424
+ if pcnt: retstr += "/{}".format(pcnt)
425
+ retstr += ">"
426
+ if runhost and runhost != lockhost: retstr += '/' + runhost
427
+ return retstr
428
+
429
+ #
430
+ # lock/unlock data request partition record
431
+ #
432
+ # lock if dolock > 0, unlock if <= 0, skip for locked on different host if 0 or 1
433
+ # force unlock if < -1 or 2
434
+ #
435
+ def lock_partition(pidx, dolock, logact = 0):
436
+
437
+ if not pidx: return 0
438
+ if logact:
439
+ logerr = logact|PgLOG.ERRLOG
440
+ logout = logact&(~PgLOG.EXITLG)
441
+ else:
442
+ logerr = PgLOG.LOGERR
443
+ logout = PgLOG.LOGWRN if dolock > 1 or dolock < 0 else 0
444
+ table = "ptrqst"
445
+ cnd = "pindex = {}".format(pidx)
446
+ fields = "pid, lockhost"
447
+ pgrec = PgDBI.pgget(table, "rindex, ptorder, " + fields, cnd, logerr)
448
+ if not pgrec: return 0 # request is gone or db error
449
+
450
+ ridx = pgrec['rindex']
451
+ pid = pgrec['pid']
452
+ host = pgrec['lockhost']
453
+ (chost, cpid) = PgLOG.current_process_info()
454
+
455
+ if pid == 0 and dolock <= 0: return pidx # no need unlock
456
+ lckpid = -pid if pid > 0 and pid == cpid and not PgUtil.pgcmp(host, chost, 1) else pid
457
+ if dolock > 0 and lckpid < 0: return pidx # no need lock again
458
+
459
+ pinfo = "{}-{}-RPT{}(Rqst{}/PTO{})".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.current_datetime(), pidx, ridx, pgrec['ptorder'])
460
+ if lckpid > 0:
461
+ lmsg = "{} Locked by {}/{}".format(pinfo, pid, host)
462
+ if check_process_running_status(host, pid, dolock, lmsg, logout): return -pidx
463
+
464
+ record = {}
465
+ if dolock > 0:
466
+ if pid != cpid: record['pid'] = cpid
467
+ if host != chost: record['lockhost'] = chost
468
+ if record: record['locktime'] = int(time.time())
469
+ else:
470
+ if pid: record['pid'] = 0
471
+ if host: record['lockhost'] = ""
472
+ if not record: return pidx
473
+
474
+ lkrec = PgDBI.pgget(table, fields, cnd, logerr|PgLOG.DOLOCK)
475
+ if not lkrec: return end_db_transaction(0) # request partition is gone or db error
476
+
477
+ if (not lkrec['pid'] or
478
+ lkrec['pid'] == pid and PgUtil.pgcmp(lkrec['lockhost'], host, 1) == 0 or
479
+ lkrec['pid'] == cpid and PgUtil.pgcmp(lkrec['lockhost'], chost, 1) == 0):
480
+ lmsg = update_partition_lock(ridx, record, logout)
481
+ if lmsg:
482
+ if logout: PgLOG.pglog("{}: {}".format(pinfo, lmsg), logout)
483
+ pidx = -pidx
484
+ elif not PgDBI.pgupdt(table, record, cnd, logerr):
485
+ if logout: PgLOG.pglog(pinfo + ": error update lock", logout)
486
+ pidx = -pidx
487
+ else:
488
+ PgLOG.pglog("{}: Relocked {}/{}".format(pinfo, lkrec['pid'], lkrec['lockhost']), logout)
489
+ pidx = -pidx
490
+
491
+ return end_db_transaction(pidx)
492
+
493
+ #
494
+ # lock dsrqst partition record for given cidx, pid and host
495
+ #
496
+ def lock_host_partition(pidx, pid, host, logact = 0):
497
+
498
+ if not (pidx and pid): return 0
499
+ if logact:
500
+ logerr = logact|PgLOG.ERRLOG
501
+ logout = logact&(~PgLOG.EXITLG)
502
+ else:
503
+ logerr = PgLOG.LOGERR
504
+ logout = 0
505
+ table = "ptrqst"
506
+ cnd = "pindex = {}".format(pidx)
507
+ fields = "pid, lockhost"
508
+ pgrec = PgDBI.pgget(table, "rindex, ptorder, " + fields, cnd, logerr)
509
+ if not pgrec: return 0 # dscheck is gone or db error
510
+
511
+ ridx = pgrec['rindex']
512
+ pinfo = "{}-{}-RPT{}(Rqst{}/PTO{})".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.current_datetime(), pidx, ridx, pgrec['ptorder'])
513
+ if pgrec['pid']:
514
+ if pid == pgrec['pid'] and PgUtil.pgcmp(pgrec['lockhost'], host, 1) == 0: return pidx
515
+ if logout:
516
+ lmsg = "{} Locked by {}/{}".format(pinfo, pid, host)
517
+ PgLOG.pglog(lmsg +": Cannot Lock", logout)
518
+ return -pidx
519
+
520
+ record = {}
521
+ record['pid'] = pid
522
+ record['lockhost'] = host
523
+ record['locktime'] = int(time.time())
524
+
525
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr|PgLOG.DOLOCK)
526
+ if not pgrec: return end_db_transaction(0)
527
+
528
+ if not pgrec['pid'] or pid == pgrec['pid'] and PgUtil.pgcmp(pgrec['lockhost'], host, 1) == 0:
529
+ lmsg = update_partition_lock(ridx, record, logout)
530
+ if lmsg:
531
+ if logout: PgLOG.pglog("{}: {}".format(pinfo, lmsg), logout)
532
+ pidx = -pidx
533
+ elif not PgDBI.pgupdt(table, record, cnd, logerr):
534
+ if logout: PgLOG.pglog(pinfo + ": error update lock", logout)
535
+ pidx = -pidx
536
+ else:
537
+ if logout: PgLOG.pglog("{}: Relocked {}/{}".format(pinfo, pgrec['pid'], pgrec['lockhost']), logout)
538
+ pidx = -pidx
539
+
540
+ return end_db_transaction(pidx)
541
+
542
+ #
543
+ # update dsrqst lock info for given partition lock status
544
+ # Return None if all is fine; error message otherwise
545
+ #
546
+ def update_partition_lock(ridx, ptrec, logact = 0):
547
+
548
+ if not ridx: return 0
549
+ if logact:
550
+ logerr = logact|PgLOG.ERRLOG
551
+ logout = logact&(~PgLOG.EXITLG)
552
+ else:
553
+ logerr = PgLOG.LOGERR
554
+ logout = PgLOG.LOGWRN
555
+ table = "dsrqst"
556
+ lockhost = "partition"
557
+ cnd = "rindex = {}".format(ridx)
558
+ pgrec = PgDBI.pgget(table, "pid, lockhost", cnd, logact|PgLOG.DOLOCK)
559
+ if not pgrec: return "Error get Rqst{} record".format(ridx) # should not happen
560
+
561
+ if pgrec['pid'] > 0 and pgrec['lockhost'] != lockhost:
562
+ return "Rqst{} locked by non-lockhost process ({}/{})".format(ridx, pgrec['pid'], pgrec['lockhost'])
563
+
564
+ record = {}
565
+ if ptrec['pid'] > 0:
566
+ record['pid'] = pgrec['pid'] + 1
567
+ record['lockhost'] = lockhost
568
+ record['locktime'] = ptrec['locktime']
569
+ else:
570
+ if pgrec['pid'] > 1:
571
+ pcnt = PgDBI.pgget('ptrqst', '', cnd + " AND pid > 0")
572
+ if pgrec['pid'] > pcnt: pgrec['pid'] = pcnt
573
+ record['pid'] = pgrec['pid'] - 1
574
+ record['lockhost'] = lockhost
575
+ else:
576
+ record['pid'] = 0
577
+ record['lockhost'] = ''
578
+ if not PgDBI.pgupdt(table, record, cnd, logact):
579
+ return "Error update Rqst{} lock".format(ridx)
580
+
581
+ return None
582
+
583
+ #
584
+ # lock/unlock dataset record for Quasar Backup
585
+ #
586
+ # lock if dolock > 0, unlock if <= 0, skip for locked on different host if 0 or 1,
587
+ # unlock dead process if < -1 or 2, force unlock if -2
588
+ #
589
+ def lock_dataset(dsid, dolock, logact = 0):
590
+
591
+ if not dsid: return 0
592
+ if logact:
593
+ logerr = logact|PgLOG.ERRLOG
594
+ logout = logact&(~PgLOG.EXITLG)
595
+ else:
596
+ logerr = PgLOG.LOGERR
597
+ logout = PgLOG.LOGWRN if dolock > 1 or dolock < 0 else 0
598
+ table = "dataset"
599
+ cnd = "dsid = '{}'".format(dsid)
600
+ fields = "pid, lockhost"
601
+ pgrec = PgDBI.pgget(table, fields, cnd, logerr)
602
+ if not pgrec: return 0 # dataset not exists
603
+
604
+ pid = pgrec['pid']
605
+ host = pgrec['lockhost']
606
+ (chost, cpid) = PgLOG.current_process_info()
607
+
608
+ if pid == 0 and dolock <= 0: return 1 # no need unlock
609
+ lckpid = -pid if pid > 0 and pid == cpid and not PgUtil.pgcmp(host, chost, 1) else pid
610
+ if dolock > 0 and lckpid < 0: return 1 # no need lock again
611
+
612
+ dinfo = "{}-{}-{}".format(PgLOG.PGLOG['HOSTNAME'], PgLOG.current_datetime(), dsid)
613
+ if lckpid > 0:
614
+ lmsg = "{} Locked by {}/{}".format(dinfo, pid, host)
615
+ if check_process_running_status(host, pid, dolock, lmsg, logout): return -1
616
+
617
+ record = {}
618
+ if dolock > 0:
619
+ if pid != cpid: record['pid'] = cpid
620
+ if host != chost: record['lockhost'] = chost
621
+ else:
622
+ if pid: record['pid'] = 0
623
+ if not record: return 1
624
+
625
+ lkrec = PgDBI.pgget(table, fields, cnd, logerr|PgLOG.DOLOCK)
626
+ if not lkrec: return end_db_transaction(0) # dscheck is gone or db error
627
+
628
+ lstat = 1
629
+ if (not lkrec['pid'] or
630
+ lkrec['pid'] == pid and PgUtil.pgcmp(lkrec['lockhost'], host, 1) == 0 or
631
+ lkrec['pid'] == cpid and PgUtil.pgcmp(lkrec['lockhost'], chost, 1) == 0):
632
+ if not PgDBI.pgupdt(table, record, cnd, logerr):
633
+ if logout: PgLOG.pglog(dinfo + ": Error update lock", logout)
634
+ lstat = -1
635
+ else:
636
+ if logout: PgLOG.pglog("{}: Relocked {}/{}".format(dinfo, lkrec['pid'], lkrec['lockhost']), logout)
637
+ lstat = -1
638
+
639
+ return end_db_transaction(lstat)