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