copyparty 1.12.1__py3-none-any.whl → 1.13.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.
copyparty/up2k.py CHANGED
@@ -88,6 +88,9 @@ CV_EXTS = set(zsg.split(","))
88
88
  HINT_HISTPATH = "you could try moving the database to another location (preferably an SSD or NVME drive) using either the --hist argument (global option for all volumes), or the hist volflag (just for this volume)"
89
89
 
90
90
 
91
+ VF_CAREFUL = {"mv_re_t": 5, "rm_re_t": 5, "mv_re_r": 0.1, "rm_re_r": 0.1}
92
+
93
+
91
94
  class Dbw(object):
92
95
  def __init__(self, c , n , t ) :
93
96
  self.c = c
@@ -133,6 +136,7 @@ class Up2k(object):
133
136
  self.need_rescan = set()
134
137
  self.db_act = 0.0
135
138
 
139
+ self.reg_mutex = threading.Lock()
136
140
  self.registry = {}
137
141
  self.flags = {}
138
142
  self.droppable = {}
@@ -140,7 +144,7 @@ class Up2k(object):
140
144
  self.volsize = {}
141
145
  self.volstate = {}
142
146
  self.vol_act = {}
143
- self.busy_aps = set()
147
+ self.busy_aps = {}
144
148
  self.dupesched = {}
145
149
  self.snap_prev = {}
146
150
 
@@ -197,11 +201,15 @@ class Up2k(object):
197
201
  Daemon(self.deferred_init, "up2k-deferred-init")
198
202
 
199
203
  def reload(self, rescan_all_vols ) :
200
- """mutex me"""
204
+ """mutex(main) me"""
201
205
  self.log("reload #{} scheduled".format(self.gid + 1))
202
206
  all_vols = self.asrv.vfs.all_vols
203
207
 
204
- scan_vols = [k for k, v in all_vols.items() if v.realpath not in self.registry]
208
+ with self.reg_mutex:
209
+ scan_vols = [
210
+ k for k, v in all_vols.items() if v.realpath not in self.registry
211
+ ]
212
+
205
213
  if rescan_all_vols:
206
214
  scan_vols = list(all_vols.keys())
207
215
 
@@ -214,7 +222,7 @@ class Up2k(object):
214
222
  if self.stop:
215
223
  # up-mt consistency not guaranteed if init is interrupted;
216
224
  # drop caches for a full scan on next boot
217
- with self.mutex:
225
+ with self.mutex, self.reg_mutex:
218
226
  self._drop_caches()
219
227
 
220
228
  if self.pp:
@@ -280,10 +288,27 @@ class Up2k(object):
280
288
  min(1000 * 24 * 60 * 60 - 1, time.time() - self.db_act)
281
289
  ),
282
290
  }
283
- return json.dumps(ret, indent=4)
291
+ return json.dumps(ret, separators=(",\n", ": "))
292
+
293
+ def find_job_by_ap(self, ptop , ap ) :
294
+ try:
295
+ if ANYWIN:
296
+ ap = ap.replace("\\", "/")
297
+
298
+ vp = ap[len(ptop) :].strip("/")
299
+ dn, fn = vsplit(vp)
300
+ with self.reg_mutex:
301
+ tab2 = self.registry[ptop]
302
+ for job in tab2.values():
303
+ if job["prel"] == dn and job["name"] == fn:
304
+ return json.dumps(job, separators=(",\n", ": "))
305
+ except:
306
+ pass
307
+
308
+ return "{}"
284
309
 
285
310
  def get_unfinished_by_user(self, uname, ip) :
286
- if PY2 or not self.mutex.acquire(timeout=2):
311
+ if PY2 or not self.reg_mutex.acquire(timeout=2):
287
312
  return '[{"timeout":1}]'
288
313
 
289
314
  ret = []
@@ -312,17 +337,25 @@ class Up2k(object):
312
337
  )
313
338
  ret.append(zt5)
314
339
  finally:
315
- self.mutex.release()
340
+ self.reg_mutex.release()
341
+
342
+ if ANYWIN:
343
+ ret = [(x[0], x[1].replace("\\", "/"), x[2], x[3], x[4]) for x in ret]
316
344
 
317
345
  ret.sort(reverse=True)
318
346
  ret2 = [
319
- {"at": at, "vp": "/" + vp, "pd": 100 - ((nn * 100) // (nh or 1)), "sz": sz}
347
+ {
348
+ "at": at,
349
+ "vp": "/" + quotep(vp),
350
+ "pd": 100 - ((nn * 100) // (nh or 1)),
351
+ "sz": sz,
352
+ }
320
353
  for (at, vp, sz, nn, nh) in ret
321
354
  ]
322
- return json.dumps(ret2, indent=0)
355
+ return json.dumps(ret2, separators=(",\n", ": "))
323
356
 
324
357
  def get_unfinished(self) :
325
- if PY2 or not self.mutex.acquire(timeout=0.5):
358
+ if PY2 or not self.reg_mutex.acquire(timeout=0.5):
326
359
  return ""
327
360
 
328
361
  ret = {}
@@ -344,17 +377,17 @@ class Up2k(object):
344
377
 
345
378
  ret[ptop] = (nbytes, nfiles)
346
379
  finally:
347
- self.mutex.release()
380
+ self.reg_mutex.release()
348
381
 
349
- return json.dumps(ret, indent=4)
382
+ return json.dumps(ret, separators=(",\n", ": "))
350
383
 
351
384
  def get_volsize(self, ptop ) :
352
- with self.mutex:
385
+ with self.reg_mutex:
353
386
  return self._get_volsize(ptop)
354
387
 
355
388
  def get_volsizes(self, ptops ) :
356
389
  ret = []
357
- with self.mutex:
390
+ with self.reg_mutex:
358
391
  for ptop in ptops:
359
392
  ret.append(self._get_volsize(ptop))
360
393
 
@@ -382,7 +415,7 @@ class Up2k(object):
382
415
  def _rescan(
383
416
  self, all_vols , scan_vols , wait , fscan
384
417
  ) :
385
- """mutex me"""
418
+ """mutex(main) me"""
386
419
  if not wait and self.pp:
387
420
  return "cannot initiate; scan is already in progress"
388
421
 
@@ -664,7 +697,7 @@ class Up2k(object):
664
697
  self.log(msg, c=3)
665
698
 
666
699
  live_vols = []
667
- with self.mutex:
700
+ with self.mutex, self.reg_mutex:
668
701
  # only need to protect register_vpath but all in one go feels right
669
702
  for vol in vols:
670
703
  try:
@@ -706,7 +739,7 @@ class Up2k(object):
706
739
 
707
740
  if self.args.re_dhash or [zv for zv in vols if "e2tsr" in zv.flags]:
708
741
  self.args.re_dhash = False
709
- with self.mutex:
742
+ with self.mutex, self.reg_mutex:
710
743
  self._drop_caches()
711
744
 
712
745
  for vol in vols:
@@ -783,7 +816,9 @@ class Up2k(object):
783
816
  self.volstate[vol.vpath] = "online (mtp soon)"
784
817
 
785
818
  for vol in need_vac:
786
- reg = self.register_vpath(vol.realpath, vol.flags)
819
+ with self.mutex, self.reg_mutex:
820
+ reg = self.register_vpath(vol.realpath, vol.flags)
821
+
787
822
  assert reg
788
823
  cur, _ = reg
789
824
  with self.mutex:
@@ -797,7 +832,9 @@ class Up2k(object):
797
832
  if vol.flags["dbd"] == "acid":
798
833
  continue
799
834
 
800
- reg = self.register_vpath(vol.realpath, vol.flags)
835
+ with self.mutex, self.reg_mutex:
836
+ reg = self.register_vpath(vol.realpath, vol.flags)
837
+
801
838
  try:
802
839
  assert reg
803
840
  cur, db_path = reg
@@ -844,6 +881,7 @@ class Up2k(object):
844
881
  def register_vpath(
845
882
  self, ptop , flags
846
883
  ) :
884
+ """mutex(main,reg) me"""
847
885
  histpath = self.asrv.vfs.histtab.get(ptop)
848
886
  if not histpath:
849
887
  self.log("no histpath for [{}]".format(ptop))
@@ -866,7 +904,7 @@ class Up2k(object):
866
904
  ft = "\033[0;32m{}{:.0}"
867
905
  ff = "\033[0;35m{}{:.0}"
868
906
  fv = "\033[0;36m{}:\033[90m{}"
869
- fx = set(("html_head", "rm_re_t", "rm_re_r"))
907
+ fx = set(("html_head", "rm_re_t", "rm_re_r", "mv_re_t", "mv_re_r"))
870
908
  fd = vf_bmap()
871
909
  fd.update(vf_cmap())
872
910
  fd.update(vf_vmap())
@@ -1027,7 +1065,9 @@ class Up2k(object):
1027
1065
  dev = cst.st_dev if vol.flags.get("xdev") else 0
1028
1066
 
1029
1067
  with self.mutex:
1030
- reg = self.register_vpath(top, vol.flags)
1068
+ with self.reg_mutex:
1069
+ reg = self.register_vpath(top, vol.flags)
1070
+
1031
1071
  assert reg and self.pp
1032
1072
  cur, db_path = reg
1033
1073
 
@@ -1624,7 +1664,7 @@ class Up2k(object):
1624
1664
 
1625
1665
  def _build_tags_index(self, vol ) :
1626
1666
  ptop = vol.realpath
1627
- with self.mutex:
1667
+ with self.mutex, self.reg_mutex:
1628
1668
  reg = self.register_vpath(ptop, vol.flags)
1629
1669
 
1630
1670
  assert reg and self.pp
@@ -1645,6 +1685,7 @@ class Up2k(object):
1645
1685
  return ret
1646
1686
 
1647
1687
  def _drop_caches(self) :
1688
+ """mutex(main,reg) me"""
1648
1689
  self.log("dropping caches for a full filesystem scan")
1649
1690
  for vol in self.asrv.vfs.all_vols.values():
1650
1691
  reg = self.register_vpath(vol.realpath, vol.flags)
@@ -1820,7 +1861,7 @@ class Up2k(object):
1820
1861
  params ,
1821
1862
  flt ,
1822
1863
  ) :
1823
- """mutex me"""
1864
+ """mutex(main) me"""
1824
1865
  n = 0
1825
1866
  c2 = cur.connection.cursor()
1826
1867
  tf = tempfile.SpooledTemporaryFile(1024 * 1024 * 8, "w+b", prefix="cpp-tq-")
@@ -2154,7 +2195,7 @@ class Up2k(object):
2154
2195
  ip ,
2155
2196
  at ,
2156
2197
  ) :
2157
- """will mutex"""
2198
+ """will mutex(main)"""
2158
2199
  assert self.mtag
2159
2200
 
2160
2201
  try:
@@ -2186,7 +2227,7 @@ class Up2k(object):
2186
2227
  abspath ,
2187
2228
  tags ,
2188
2229
  ) :
2189
- """mutex me"""
2230
+ """mutex(main) me"""
2190
2231
  assert self.mtag
2191
2232
 
2192
2233
  if not bos.path.isfile(abspath):
@@ -2471,28 +2512,36 @@ class Up2k(object):
2471
2512
 
2472
2513
  cur.connection.commit()
2473
2514
 
2474
- def _job_volchk(self, cj ) :
2475
- if not self.register_vpath(cj["ptop"], cj["vcfg"]):
2476
- if cj["ptop"] not in self.registry:
2477
- raise Pebkac(410, "location unavailable")
2478
-
2479
- def handle_json(self, cj , busy_aps ) :
2515
+ def handle_json(
2516
+ self, cj , busy_aps
2517
+ ) :
2518
+ # busy_aps is u2fh (always undefined if -j0) so this is safe
2480
2519
  self.busy_aps = busy_aps
2520
+ got_lock = False
2481
2521
  try:
2482
2522
  # bit expensive; 3.9=10x 3.11=2x
2483
2523
  if self.mutex.acquire(timeout=10):
2484
- self._job_volchk(cj)
2485
- self.mutex.release()
2524
+ got_lock = True
2525
+ with self.reg_mutex:
2526
+ return self._handle_json(cj)
2486
2527
  else:
2487
2528
  t = "cannot receive uploads right now;\nserver busy with {}.\nPlease wait; the client will retry..."
2488
2529
  raise Pebkac(503, t.format(self.blocked or "[unknown]"))
2489
2530
  except TypeError:
2490
2531
  if not PY2:
2491
2532
  raise
2492
- with self.mutex:
2493
- self._job_volchk(cj)
2533
+ with self.mutex, self.reg_mutex:
2534
+ return self._handle_json(cj)
2535
+ finally:
2536
+ if got_lock:
2537
+ self.mutex.release()
2494
2538
 
2539
+ def _handle_json(self, cj ) :
2495
2540
  ptop = cj["ptop"]
2541
+ if not self.register_vpath(ptop, cj["vcfg"]):
2542
+ if ptop not in self.registry:
2543
+ raise Pebkac(410, "location unavailable")
2544
+
2496
2545
  cj["name"] = sanitize_fn(cj["name"], "", [".prologue.html", ".epilogue.html"])
2497
2546
  cj["poke"] = now = self.db_act = self.vol_act[ptop] = time.time()
2498
2547
  wark = self._get_wark(cj)
@@ -2507,7 +2556,7 @@ class Up2k(object):
2507
2556
  # refuse out-of-order / multithreaded uploading if sprs False
2508
2557
  sprs = self.fstab.get(pdir) != "ng"
2509
2558
 
2510
- with self.mutex:
2559
+ if True:
2511
2560
  jcur = self.cur.get(ptop)
2512
2561
  reg = self.registry[ptop]
2513
2562
  vfs = self.asrv.vfs.all_vols[cj["vtop"]]
@@ -2945,7 +2994,7 @@ class Up2k(object):
2945
2994
  def handle_chunk(
2946
2995
  self, ptop , wark , chash
2947
2996
  ) :
2948
- with self.mutex:
2997
+ with self.mutex, self.reg_mutex:
2949
2998
  self.db_act = self.vol_act[ptop] = time.time()
2950
2999
  job = self.registry[ptop].get(wark)
2951
3000
  if not job:
@@ -2988,7 +3037,7 @@ class Up2k(object):
2988
3037
  return chunksize, ofs, path, job["lmod"], job["sprs"]
2989
3038
 
2990
3039
  def release_chunk(self, ptop , wark , chash ) :
2991
- with self.mutex:
3040
+ with self.reg_mutex:
2992
3041
  job = self.registry[ptop].get(wark)
2993
3042
  if job:
2994
3043
  job["busy"].pop(chash, None)
@@ -2996,7 +3045,7 @@ class Up2k(object):
2996
3045
  return True
2997
3046
 
2998
3047
  def confirm_chunk(self, ptop , wark , chash ) :
2999
- with self.mutex:
3048
+ with self.mutex, self.reg_mutex:
3000
3049
  self.db_act = self.vol_act[ptop] = time.time()
3001
3050
  try:
3002
3051
  job = self.registry[ptop][wark]
@@ -3019,16 +3068,16 @@ class Up2k(object):
3019
3068
 
3020
3069
  if self.args.nw:
3021
3070
  self.regdrop(ptop, wark)
3022
- return ret, dst
3023
3071
 
3024
3072
  return ret, dst
3025
3073
 
3026
3074
  def finish_upload(self, ptop , wark , busy_aps ) :
3027
3075
  self.busy_aps = busy_aps
3028
- with self.mutex:
3076
+ with self.mutex, self.reg_mutex:
3029
3077
  self._finish_upload(ptop, wark)
3030
3078
 
3031
3079
  def _finish_upload(self, ptop , wark ) :
3080
+ """mutex(main,reg) me"""
3032
3081
  try:
3033
3082
  job = self.registry[ptop][wark]
3034
3083
  pdir = djoin(job["ptop"], job["prel"])
@@ -3041,12 +3090,11 @@ class Up2k(object):
3041
3090
  t = "finish_upload {} with remaining chunks {}"
3042
3091
  raise Pebkac(500, t.format(wark, job["need"]))
3043
3092
 
3044
- # self.log("--- " + wark + " " + dst + " finish_upload atomic " + dst, 4)
3045
- atomic_move(src, dst)
3046
-
3047
3093
  upt = job.get("at") or time.time()
3048
3094
  vflags = self.flags[ptop]
3049
3095
 
3096
+ atomic_move(self.log, src, dst, vflags)
3097
+
3050
3098
  times = (int(time.time()), int(job["lmod"]))
3051
3099
  self.log(
3052
3100
  "no more chunks, setting times {} ({}) on {}".format(
@@ -3102,6 +3150,7 @@ class Up2k(object):
3102
3150
  cur.connection.commit()
3103
3151
 
3104
3152
  def regdrop(self, ptop , wark ) :
3153
+ """mutex(main,reg) me"""
3105
3154
  olds = self.droppable[ptop]
3106
3155
  if wark:
3107
3156
  olds.append(wark)
@@ -3196,16 +3245,23 @@ class Up2k(object):
3196
3245
  at ,
3197
3246
  skip_xau = False,
3198
3247
  ) :
3248
+ """mutex(main) me"""
3199
3249
  self.db_rm(db, rd, fn, sz)
3200
3250
 
3251
+ if not ip:
3252
+ db_ip = ""
3253
+ else:
3254
+ # plugins may expect this to look like an actual IP
3255
+ db_ip = "1.1.1.1" if self.args.no_db_ip else ip
3256
+
3201
3257
  sql = "insert into up values (?,?,?,?,?,?,?)"
3202
- v = (wark, int(ts), sz, rd, fn, ip or "", int(at or 0))
3258
+ v = (wark, int(ts), sz, rd, fn, db_ip, int(at or 0))
3203
3259
  try:
3204
3260
  db.execute(sql, v)
3205
3261
  except:
3206
3262
  assert self.mem_cur
3207
3263
  rd, fn = s3enc(self.mem_cur, rd, fn)
3208
- v = (wark, int(ts), sz, rd, fn, ip or "", int(at or 0))
3264
+ v = (wark, int(ts), sz, rd, fn, db_ip, int(at or 0))
3209
3265
  db.execute(sql, v)
3210
3266
 
3211
3267
  self.volsize[db] += sz
@@ -3309,7 +3365,7 @@ class Up2k(object):
3309
3365
  vn, rem = self.asrv.vfs.get(vpath, uname, *permsets[0])
3310
3366
  vn, rem = vn.get_dbv(rem)
3311
3367
  ptop = vn.realpath
3312
- with self.mutex:
3368
+ with self.mutex, self.reg_mutex:
3313
3369
  abrt_cfg = self.flags.get(ptop, {}).get("u2abort", 1)
3314
3370
  addr = (ip or "\n") if abrt_cfg in (1, 2) else ""
3315
3371
  user = (uname or "\n") if abrt_cfg in (1, 3) else ""
@@ -3317,7 +3373,10 @@ class Up2k(object):
3317
3373
  for wark, job in reg.items():
3318
3374
  if (user and user != job["user"]) or (addr and addr != job["addr"]):
3319
3375
  continue
3320
- if djoin(job["prel"], job["name"]) == rem:
3376
+ jrem = djoin(job["prel"], job["name"])
3377
+ if ANYWIN:
3378
+ jrem = jrem.replace("\\", "/")
3379
+ if jrem == rem:
3321
3380
  if job["ptop"] != ptop:
3322
3381
  t = "job.ptop [%s] != vol.ptop [%s] ??"
3323
3382
  raise Exception(t % (job["ptop"] != ptop))
@@ -3413,7 +3472,7 @@ class Up2k(object):
3413
3472
  continue
3414
3473
 
3415
3474
  n_files += 1
3416
- with self.mutex:
3475
+ with self.mutex, self.reg_mutex:
3417
3476
  cur = None
3418
3477
  try:
3419
3478
  ptop = dbv.realpath
@@ -3531,6 +3590,7 @@ class Up2k(object):
3531
3590
  def _mv_file(
3532
3591
  self, uname , svp , dvp , curs
3533
3592
  ) :
3593
+ """mutex(main) me; will mutex(reg)"""
3534
3594
  svn, srem = self.asrv.vfs.get(svp, uname, True, False, True)
3535
3595
  svn, srem = svn.get_dbv(srem)
3536
3596
 
@@ -3611,7 +3671,9 @@ class Up2k(object):
3611
3671
  if c2 and c2 != c1:
3612
3672
  self._copy_tags(c1, c2, w)
3613
3673
 
3614
- has_dupes = self._forget_file(svn.realpath, srem, c1, w, is_xvol, fsize)
3674
+ with self.reg_mutex:
3675
+ has_dupes = self._forget_file(svn.realpath, srem, c1, w, is_xvol, fsize)
3676
+
3615
3677
  if not is_xvol:
3616
3678
  has_dupes = self._relink(w, svn.realpath, srem, dabs)
3617
3679
 
@@ -3650,7 +3712,7 @@ class Up2k(object):
3650
3712
  self._symlink(dlink, dabs, dvn.flags, lmod=ftime)
3651
3713
  wunlink(self.log, sabs, svn.flags)
3652
3714
  else:
3653
- atomic_move(sabs, dabs)
3715
+ atomic_move(self.log, sabs, dabs, svn.flags)
3654
3716
 
3655
3717
  except OSError as ex:
3656
3718
  if ex.errno != errno.EXDEV:
@@ -3741,7 +3803,10 @@ class Up2k(object):
3741
3803
  drop_tags ,
3742
3804
  sz ,
3743
3805
  ) :
3744
- """forgets file in db, fixes symlinks, does not delete"""
3806
+ """
3807
+ mutex(main,reg) me
3808
+ forgets file in db, fixes symlinks, does not delete
3809
+ """
3745
3810
  srd, sfn = vsplit(vrem)
3746
3811
  has_dupes = False
3747
3812
  self.log("forgetting {}".format(vrem))
@@ -3827,8 +3892,7 @@ class Up2k(object):
3827
3892
  self.log("linkswap [{}] and [{}]".format(sabs, slabs))
3828
3893
  mt = bos.path.getmtime(slabs, False)
3829
3894
  flags = self.flags.get(ptop) or {}
3830
- wunlink(self.log, slabs, flags)
3831
- bos.rename(sabs, slabs)
3895
+ atomic_move(self.log, sabs, slabs, flags)
3832
3896
  bos.utime(slabs, (int(time.time()), int(mt)), False)
3833
3897
  self._symlink(slabs, sabs, flags, False)
3834
3898
  full[slabs] = (ptop, rem)
@@ -4067,7 +4131,7 @@ class Up2k(object):
4067
4131
  self.do_snapshot()
4068
4132
 
4069
4133
  def do_snapshot(self) :
4070
- with self.mutex:
4134
+ with self.mutex, self.reg_mutex:
4071
4135
  for k, reg in self.registry.items():
4072
4136
  self._snap_reg(k, reg)
4073
4137
 
@@ -4135,11 +4199,11 @@ class Up2k(object):
4135
4199
 
4136
4200
  path2 = "{}.{}".format(path, os.getpid())
4137
4201
  body = {"droppable": self.droppable[ptop], "registry": reg}
4138
- j = json.dumps(body, indent=2, sort_keys=True).encode("utf-8")
4202
+ j = json.dumps(body, sort_keys=True, separators=(",\n", ": ")).encode("utf-8")
4139
4203
  with gzip.GzipFile(path2, "wb") as f:
4140
4204
  f.write(j)
4141
4205
 
4142
- atomic_move(path2, path)
4206
+ atomic_move(self.log, path2, path, VF_CAREFUL)
4143
4207
 
4144
4208
  self.log("snap: {} |{}|".format(path, len(reg.keys())))
4145
4209
  self.snap_prev[ptop] = etag
@@ -4208,7 +4272,7 @@ class Up2k(object):
4208
4272
  raise Exception("invalid hash task")
4209
4273
 
4210
4274
  try:
4211
- if not self._hash_t(task):
4275
+ if not self._hash_t(task) and self.stop:
4212
4276
  return
4213
4277
  except Exception as ex:
4214
4278
  self.log("failed to hash %s: %s" % (task, ex), 1)
@@ -4218,7 +4282,7 @@ class Up2k(object):
4218
4282
  ) :
4219
4283
  ptop, vtop, flags, rd, fn, ip, at, usr, skip_xau = task
4220
4284
  # self.log("hashq {} pop {}/{}/{}".format(self.n_hashq, ptop, rd, fn))
4221
- with self.mutex:
4285
+ with self.mutex, self.reg_mutex:
4222
4286
  if not self.register_vpath(ptop, flags):
4223
4287
  return True
4224
4288
 
@@ -4236,7 +4300,7 @@ class Up2k(object):
4236
4300
 
4237
4301
  wark = up2k_wark_from_hashlist(self.salt, inf.st_size, hashes)
4238
4302
 
4239
- with self.mutex:
4303
+ with self.mutex, self.reg_mutex:
4240
4304
  self.idx_wark(
4241
4305
  self.flags[ptop],
4242
4306
  rd,