Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1#!/usr/bin/python3 

2# 

3# Copyright (C) Citrix Systems Inc. 

4# 

5# This program is free software; you can redistribute it and/or modify 

6# it under the terms of the GNU Lesser General Public License as published 

7# by the Free Software Foundation; version 2.1 only. 

8# 

9# This program is distributed in the hope that it will be useful, 

10# but WITHOUT ANY WARRANTY; without even the implied warranty of 

11# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 

12# GNU Lesser General Public License for more details. 

13# 

14# You should have received a copy of the GNU Lesser General Public License 

15# along with this program; if not, write to the Free Software Foundation, Inc., 

16# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA 

17# 

18# Persistent reference counter. This refcounter can maintain two separate 

19# refcounts: one binary (which can have a value of 0 or 1) and one normal. The 

20# parameter "binary" specifies which of the two counters to update, while the 

21# return value is zero IFF both counters are zero 

22# 

23# Synchronization must be done at a higher level, by the users of this module 

24# 

25 

26import os 

27import util 

28from lock import Lock 

29import errno 

30 

31 

32class RefCounterException(util.SMException): 

33 pass 

34 

35 

36class RefCounter: 

37 """Persistent local-FS file-based reference counter. The 

38 operations are get() and put(), and they are atomic.""" 

39 

40 BASE_DIR = "/var/run/sm/refcount" 

41 

42 def get(obj, binary, ns=None): 

43 """Get (inc ref count) 'obj' in namespace 'ns' (optional).  

44 Returns new ref count""" 

45 if binary: 

46 return RefCounter._adjust(ns, obj, 0, 1) 

47 else: 

48 return RefCounter._adjust(ns, obj, 1, 0) 

49 get = staticmethod(get) 

50 

51 def put(obj, binary, ns=None): 

52 """Put (dec ref count) 'obj' in namespace 'ns' (optional). If ref 

53 count was zero already, this operation is a no-op. 

54 Returns new ref count""" 

55 if binary: 

56 return RefCounter._adjust(ns, obj, 0, -1) 

57 else: 

58 return RefCounter._adjust(ns, obj, -1, 0) 

59 put = staticmethod(put) 

60 

61 def set(obj, count, binaryCount, ns=None): 

62 """Set normal & binary counts explicitly to the specified values. 

63 Returns new ref count""" 

64 (obj, ns) = RefCounter._getSafeNames(obj, ns) 

65 assert(count >= 0 and binaryCount >= 0) 

66 if binaryCount > 1: 

67 raise RefCounterException("Binary count = %d > 1" % binaryCount) 

68 RefCounter._set(ns, obj, count, binaryCount) 

69 set = staticmethod(set) 

70 

71 def check(obj, ns=None): 

72 """Get the ref count values for 'obj' in namespace 'ns' (optional)""" 

73 (obj, ns) = RefCounter._getSafeNames(obj, ns) 

74 return RefCounter._get(ns, obj) 

75 check = staticmethod(check) 

76 

77 def checkLocked(obj, ns): 

78 """Lock-protected access""" 

79 lock = Lock(obj, ns) 

80 lock.acquire() 

81 try: 

82 return RefCounter.check(obj, ns) 

83 finally: 

84 lock.release() 

85 checkLocked = staticmethod(checkLocked) 

86 

87 def reset(obj, ns=None): 

88 """Reset ref counts for 'obj' in namespace 'ns' (optional) to 0.""" 

89 RefCounter.resetAll(ns, obj) 

90 reset = staticmethod(reset) 

91 

92 def resetAll(ns=None, obj=None): 

93 """Reset ref counts of 'obj' in namespace 'ns' to 0. If obj is not 

94 provided, reset all existing objects in 'ns' to 0. If neither obj nor  

95 ns are supplied, do this for all namespaces""" 

96 if obj: 

97 (obj, ns) = RefCounter._getSafeNames(obj, ns) 

98 if ns: 

99 nsList = [ns] 

100 else: 

101 if not util.pathexists(RefCounter.BASE_DIR): 

102 return 

103 try: 

104 nsList = os.listdir(RefCounter.BASE_DIR) 

105 except OSError: 

106 raise RefCounterException("failed to get namespace list") 

107 for ns in nsList: 

108 RefCounter._reset(ns, obj) 

109 resetAll = staticmethod(resetAll) 

110 

111 def _adjust(ns, obj, delta, binaryDelta): 

112 """Add 'delta' to the normal refcount and 'binaryDelta' to the binary 

113 refcount of 'obj' in namespace 'ns'.  

114 Returns new ref count""" 

115 if binaryDelta > 1 or binaryDelta < -1: 115 ↛ 116line 115 didn't jump to line 116, because the condition on line 115 was never true

116 raise RefCounterException("Binary delta = %d outside [-1;1]" % \ 

117 binaryDelta) 

118 (obj, ns) = RefCounter._getSafeNames(obj, ns) 

119 (count, binaryCount) = RefCounter._get(ns, obj) 

120 

121 newCount = count + delta 

122 newBinaryCount = binaryCount + binaryDelta 

123 if newCount < 0: 

124 util.SMlog("WARNING: decrementing normal refcount of 0") 

125 newCount = 0 

126 if newBinaryCount < 0: 

127 util.SMlog("WARNING: decrementing binary refcount of 0") 

128 newBinaryCount = 0 

129 if newBinaryCount > 1: 

130 newBinaryCount = 1 

131 util.SMlog("Refcount for %s:%s (%d, %d) + (%d, %d) => (%d, %d)" % \ 

132 (ns, obj, count, binaryCount, delta, binaryDelta, 

133 newCount, newBinaryCount)) 

134 RefCounter._set(ns, obj, newCount, newBinaryCount) 

135 return newCount + newBinaryCount 

136 _adjust = staticmethod(_adjust) 

137 

138 def _get(ns, obj): 

139 """Get the ref count values for 'obj' in namespace 'ns'""" 

140 objFile = os.path.join(RefCounter.BASE_DIR, ns, obj) 

141 (count, binaryCount) = (0, 0) 

142 if util.pathexists(objFile): 

143 (count, binaryCount) = RefCounter._readCount(objFile) 

144 return (count, binaryCount) 

145 _get = staticmethod(_get) 

146 

147 def _set(ns, obj, count, binaryCount): 

148 """Set the ref count values for 'obj' in namespace 'ns'""" 

149 util.SMlog("Refcount for %s:%s set => (%d, %db)" % \ 

150 (ns, obj, count, binaryCount)) 

151 if count == 0 and binaryCount == 0: 

152 RefCounter._removeObject(ns, obj) 

153 else: 

154 objFile = os.path.join(RefCounter.BASE_DIR, ns, obj) 

155 

156 while not RefCounter._writeCount(objFile, count, binaryCount): 

157 RefCounter._createNamespace(ns) 

158 

159 _set = staticmethod(_set) 

160 

161 def _getSafeNames(obj, ns): 

162 """Get a name that can be used as a file name""" 

163 if not ns: 

164 ns = obj.split('/')[0] 

165 if not ns: 

166 ns = "default" 

167 for char in ['/', '*', '?', '\\']: 

168 obj = obj.replace(char, "_") 

169 return (obj, ns) 

170 _getSafeNames = staticmethod(_getSafeNames) 

171 

172 def _createNamespace(ns): 

173 nsDir = os.path.join(RefCounter.BASE_DIR, ns) 

174 try: 

175 os.makedirs(nsDir) 

176 except OSError as e: 

177 if e.errno != errno.EEXIST: 

178 raise RefCounterException("failed to makedirs '%s' (%s)" % \ 

179 (nsDir, e)) 

180 _createNamespace = staticmethod(_createNamespace) 

181 

182 def _removeObject(ns, obj): 

183 nsDir = os.path.join(RefCounter.BASE_DIR, ns) 

184 objFile = os.path.join(nsDir, obj) 

185 if not util.pathexists(objFile): 

186 return 

187 try: 

188 os.unlink(objFile) 

189 except OSError: 

190 raise RefCounterException("failed to remove '%s'" % objFile) 

191 

192 try: 

193 os.rmdir(nsDir) 

194 except OSError as e: 

195 namespaceAlreadyCleanedUp = e.errno == errno.ENOENT 

196 newObjectAddedToNamespace = e.errno == errno.ENOTEMPTY 

197 

198 if namespaceAlreadyCleanedUp or newObjectAddedToNamespace: 198 ↛ 201line 198 didn't jump to line 201, because the condition on line 198 was never false

199 pass 

200 else: 

201 raise RefCounterException("failed to remove '%s'" % nsDir) 

202 _removeObject = staticmethod(_removeObject) 

203 

204 def _reset(ns, obj=None): 

205 nsDir = os.path.join(RefCounter.BASE_DIR, ns) 

206 if not util.pathexists(nsDir): 

207 return 

208 if obj: 

209 if not util.pathexists(os.path.join(nsDir, obj)): 209 ↛ 210line 209 didn't jump to line 210, because the condition on line 209 was never true

210 return 

211 objList = [obj] 

212 else: 

213 try: 

214 objList = os.listdir(nsDir) 

215 except OSError: 

216 raise RefCounterException("failed to list '%s'" % ns) 

217 for obj in objList: 

218 RefCounter._removeObject(ns, obj) 

219 _reset = staticmethod(_reset) 

220 

221 def _readCount(fn): 

222 try: 

223 f = open(fn, 'r') 

224 line = f.readline() 

225 nums = line.split() 

226 count = int(nums[0]) 

227 binaryCount = int(nums[1]) 

228 f.close() 

229 except IOError: 

230 raise RefCounterException("failed to read file '%s'" % fn) 

231 return (count, binaryCount) 

232 _readCount = staticmethod(_readCount) 

233 

234 def _writeCount(fn, count, binaryCount): 

235 try: 

236 f = open(fn, 'w') 

237 f.write("%d %d\n" % (count, binaryCount)) 

238 f.close() 

239 return True 

240 except IOError as e: 

241 fileNotFound = e.errno == errno.ENOENT 

242 if fileNotFound: 242 ↛ 244line 242 didn't jump to line 244, because the condition on line 242 was never false

243 return False 

244 raise RefCounterException("failed to write '(%d %d)' to '%s': %s" \ 

245 % (count, binaryCount, fn, e)) 

246 _writeCount = staticmethod(_writeCount) 

247 

248 def _runTests(): 

249 "Unit tests" 

250 

251 RefCounter.resetAll() 

252 

253 # A 

254 (cnt, bcnt) = RefCounter.check("X", "A") 

255 if cnt != 0 or bcnt != 0: 255 ↛ 256line 255 didn't jump to line 256, because the condition on line 255 was never true

256 print("Error: check = %d != 0 in the beginning" % cnt) 

257 return -1 

258 

259 cnt = RefCounter.get("X", False, "A") 

260 if cnt != 1: 260 ↛ 261line 260 didn't jump to line 261, because the condition on line 260 was never true

261 print("Error: count = %d != 1 after first get()" % cnt) 

262 return -1 

263 (cnt, bcnt) = RefCounter.check("X", "A") 

264 if cnt != 1: 264 ↛ 265line 264 didn't jump to line 265, because the condition on line 264 was never true

265 print("Error: check = %d != 1 after first get()" % cnt) 

266 return -1 

267 

268 cnt = RefCounter.put("X", False, "A") 

269 if cnt != 0: 269 ↛ 270line 269 didn't jump to line 270, because the condition on line 269 was never true

270 print("Error: count = %d != 0 after get-put" % cnt) 

271 return -1 

272 (cnt, bcnt) = RefCounter.check("X", "A") 

273 if cnt != 0: 273 ↛ 274line 273 didn't jump to line 274, because the condition on line 273 was never true

274 print("Error: check = %d != 0 after get-put" % cnt) 

275 return -1 

276 

277 cnt = RefCounter.get("X", False, "A") 

278 if cnt != 1: 278 ↛ 279line 278 didn't jump to line 279, because the condition on line 278 was never true

279 print("Error: count = %d != 1 after get-put-get" % cnt) 

280 return -1 

281 

282 cnt = RefCounter.get("X", False, "A") 

283 if cnt != 2: 283 ↛ 284line 283 didn't jump to line 284, because the condition on line 283 was never true

284 print("Error: count = %d != 2 after second get()" % cnt) 

285 return -1 

286 

287 cnt = RefCounter.get("X", False, "A") 

288 if cnt != 3: 288 ↛ 289line 288 didn't jump to line 289, because the condition on line 288 was never true

289 print("Error: count = %d != 3 after third get()" % cnt) 

290 return -1 

291 (cnt, bcnt) = RefCounter.check("X", "A") 

292 if cnt != 3: 292 ↛ 293line 292 didn't jump to line 293, because the condition on line 292 was never true

293 print("Error: check = %d != 3 after third get()" % cnt) 

294 return -1 

295 

296 cnt = RefCounter.put("Y", False, "A") 

297 if cnt != 0: 297 ↛ 298line 297 didn't jump to line 298, because the condition on line 297 was never true

298 print("Error: count = %d != 0 after first put()" % cnt) 

299 return -1 

300 (cnt, bcnt) = RefCounter.check("Y", "A") 

301 if cnt != 0: 301 ↛ 302line 301 didn't jump to line 302, because the condition on line 301 was never true

302 print("Error: check = %d != 0 after first put()" % cnt) 

303 return -1 

304 

305 cnt = RefCounter.put("X", False, "A") 

306 if cnt != 2: 306 ↛ 307line 306 didn't jump to line 307, because the condition on line 306 was never true

307 print("Error: count = %d != 2 after 3get-1put" % cnt) 

308 return -1 

309 

310 cnt = RefCounter.put("X", False, "A") 

311 if cnt != 1: 311 ↛ 312line 311 didn't jump to line 312, because the condition on line 311 was never true

312 print("Error: count = %d != 1 after 3get-2put" % cnt) 

313 return -1 

314 

315 cnt = RefCounter.get("X", False, "A") 

316 if cnt != 2: 316 ↛ 317line 316 didn't jump to line 317, because the condition on line 316 was never true

317 print("Error: count = %d != 2 after 4get-2put" % cnt) 

318 return -1 

319 (cnt, bcnt) = RefCounter.check("X", "A") 

320 if cnt != 2: 320 ↛ 321line 320 didn't jump to line 321, because the condition on line 320 was never true

321 print("Error: check = %d != 2 after 4get-2put" % cnt) 

322 return -1 

323 

324 cnt = RefCounter.put("X", False, "A") 

325 if cnt != 1: 325 ↛ 326line 325 didn't jump to line 326, because the condition on line 325 was never true

326 print("Error: count = %d != 0 after 4get-3put" % cnt) 

327 return -1 

328 

329 cnt = RefCounter.put("X", False, "A") 

330 if cnt != 0: 330 ↛ 331line 330 didn't jump to line 331, because the condition on line 330 was never true

331 print("Error: count = %d != 0 after 4get-4put" % cnt) 

332 return -1 

333 (cnt, bcnt) = RefCounter.check("X", "A") 

334 if cnt != 0: 334 ↛ 335line 334 didn't jump to line 335, because the condition on line 334 was never true

335 print("Error: check = %d != 0 after 4get-4put" % cnt) 

336 return -1 

337 

338 # B 

339 cnt = RefCounter.put("Z", False, "B") 

340 if cnt != 0: 340 ↛ 341line 340 didn't jump to line 341, because the condition on line 340 was never true

341 print("Error: count = %d != 0 after new put()" % cnt) 

342 return -1 

343 

344 cnt = RefCounter.get("Z", False, "B") 

345 if cnt != 1: 345 ↛ 346line 345 didn't jump to line 346, because the condition on line 345 was never true

346 print("Error: count = %d != 1 after put-get" % cnt) 

347 return -1 

348 

349 cnt = RefCounter.put("Z", False, "B") 

350 if cnt != 0: 350 ↛ 351line 350 didn't jump to line 351, because the condition on line 350 was never true

351 print("Error: count = %d != 0 after put-get-put" % cnt) 

352 return -1 

353 (cnt, bcnt) = RefCounter.check("Z", "B") 

354 if cnt != 0: 354 ↛ 355line 354 didn't jump to line 355, because the condition on line 354 was never true

355 print("Error: check = %d != 0 after put-get-put" % cnt) 

356 return -1 

357 

358 cnt = RefCounter.get("Z", False, "B") 

359 if cnt != 1: 359 ↛ 360line 359 didn't jump to line 360, because the condition on line 359 was never true

360 print("Error: count = %d != 1 after put-get-put-get" % cnt) 

361 return -1 

362 (cnt, bcnt) = RefCounter.check("Z", "B") 

363 if cnt != 1: 363 ↛ 364line 363 didn't jump to line 364, because the condition on line 363 was never true

364 print("Error: check = %d != 1 after put-get-put-get" % cnt) 

365 return -1 

366 

367 # set 

368 (cnt, bcnt) = RefCounter.check("a/b") 

369 if cnt != 0: 369 ↛ 370line 369 didn't jump to line 370, because the condition on line 369 was never true

370 print("Error: count = %d != 0 initially" % cnt) 

371 return -1 

372 RefCounter.set("a/b", 2, 0) 

373 (cnt, bcnt) = RefCounter.check("a/b") 

374 if cnt != 2 or bcnt != 0: 374 ↛ 375line 374 didn't jump to line 375, because the condition on line 374 was never true

375 print("Error: count = (%d,%d) != (2,0) after set(2,0)" % (cnt, bcnt)) 

376 return -1 

377 cnt = RefCounter.put("a/b", False) 

378 if cnt != 1: 378 ↛ 379line 378 didn't jump to line 379, because the condition on line 378 was never true

379 print("Error: count = %d != 1 after set(2)-put" % cnt) 

380 return -1 

381 cnt = RefCounter.get("a/b", False) 

382 if cnt != 2: 382 ↛ 383line 382 didn't jump to line 383, because the condition on line 382 was never true

383 print("Error: count = %d != 2 after set(2)-put-get" % cnt) 

384 return -1 

385 RefCounter.set("a/b", 100, 0) 

386 (cnt, bcnt) = RefCounter.check("a/b") 

387 if cnt != 100 or bcnt != 0: 387 ↛ 388line 387 didn't jump to line 388, because the condition on line 387 was never true

388 print("Error: cnt,bcnt = (%d,%d) != (100,0) after set(100,0)" % \ 

389 (cnt, bcnt)) 

390 return -1 

391 cnt = RefCounter.get("a/b", False) 

392 if cnt != 101: 392 ↛ 393line 392 didn't jump to line 393, because the condition on line 392 was never true

393 print("Error: count = %d != 101 after get" % cnt) 

394 return -1 

395 RefCounter.set("a/b", 100, 1) 

396 (cnt, bcnt) = RefCounter.check("a/b") 

397 if cnt != 100 or bcnt != 1: 397 ↛ 398line 397 didn't jump to line 398, because the condition on line 397 was never true

398 print("Error: cnt,bcnt = (%d,%d) != (100,1) after set(100,1)" % \ 

399 (cnt, bcnt)) 

400 return -1 

401 RefCounter.reset("a/b") 

402 (cnt, bcnt) = RefCounter.check("a/b") 

403 if cnt != 0: 403 ↛ 404line 403 didn't jump to line 404, because the condition on line 403 was never true

404 print("Error: check = %d != 0 after reset" % cnt) 

405 return -1 

406 

407 # binary 

408 cnt = RefCounter.get("A", True) 

409 if cnt != 1: 409 ↛ 410line 409 didn't jump to line 410, because the condition on line 409 was never true

410 print("Error: count = %d != 1 after get(bin)" % cnt) 

411 return -1 

412 cnt = RefCounter.get("A", True) 

413 if cnt != 1: 413 ↛ 414line 413 didn't jump to line 414, because the condition on line 413 was never true

414 print("Error: count = %d != 1 after get(bin)*2" % cnt) 

415 return -1 

416 cnt = RefCounter.put("A", True) 

417 if cnt != 0: 417 ↛ 418line 417 didn't jump to line 418, because the condition on line 417 was never true

418 print("Error: count = %d != 0 after get(bin)*2-put(bin)" % cnt) 

419 return -1 

420 cnt = RefCounter.put("A", True) 

421 if cnt != 0: 421 ↛ 422line 421 didn't jump to line 422, because the condition on line 421 was never true

422 print("Error: count = %d != 0 after get(bin)*2-put(bin)*2" % cnt) 

423 return -1 

424 try: 

425 RefCounter.set("A", 0, 2) 

426 print("Error: set(0,2) was allowed") 

427 return -1 

428 except RefCounterException: 

429 pass 

430 cnt = RefCounter.get("A", True) 

431 if cnt != 1: 431 ↛ 432line 431 didn't jump to line 432, because the condition on line 431 was never true

432 print("Error: count = %d != 1 after get(bin)" % cnt) 

433 return -1 

434 cnt = RefCounter.get("A", False) 

435 if cnt != 2: 435 ↛ 436line 435 didn't jump to line 436, because the condition on line 435 was never true

436 print("Error: count = %d != 2 after get(bin)-get" % cnt) 

437 return -1 

438 cnt = RefCounter.get("A", False) 

439 if cnt != 3: 439 ↛ 440line 439 didn't jump to line 440, because the condition on line 439 was never true

440 print("Error: count = %d != 3 after get(bin)-get-get" % cnt) 

441 return -1 

442 cnt = RefCounter.get("A", True) 

443 if cnt != 3: 443 ↛ 444line 443 didn't jump to line 444, because the condition on line 443 was never true

444 print("Error: count = %d != 3 after get(bin)-get*2-get(bin)" % cnt) 

445 return -1 

446 cnt = RefCounter.put("A", False) 

447 if cnt != 2: 447 ↛ 448line 447 didn't jump to line 448, because the condition on line 447 was never true

448 print("Error: count = %d != 2 after get(bin)*2-get*2-put" % cnt) 

449 return -1 

450 cnt = RefCounter.put("A", True) 

451 if cnt != 1: 451 ↛ 452line 451 didn't jump to line 452, because the condition on line 451 was never true

452 print("Error: cnt = %d != 1 after get(b)*2-get*2-put-put(b)" % cnt) 

453 return -1 

454 cnt = RefCounter.put("A", False) 

455 if cnt != 0: 455 ↛ 456line 455 didn't jump to line 456, because the condition on line 455 was never true

456 print("Error: cnt = %d != 0 after get(b)*2-get*2-put*2-put(b)" % cnt) 

457 return -1 

458 

459 # names 

460 cnt = RefCounter.get("Z", False) 

461 if cnt != 1: 461 ↛ 462line 461 didn't jump to line 462, because the condition on line 461 was never true

462 print("Error: count = %d != 1 after get (no ns 1)" % cnt) 

463 return -1 

464 

465 cnt = RefCounter.get("Z/", False) 

466 if cnt != 1: 466 ↛ 467line 466 didn't jump to line 467, because the condition on line 466 was never true

467 print("Error: count = %d != 1 after get (no ns 2)" % cnt) 

468 return -1 

469 

470 cnt = RefCounter.get("/Z", False) 

471 if cnt != 1: 471 ↛ 472line 471 didn't jump to line 472, because the condition on line 471 was never true

472 print("Error: count = %d != 1 after get (no ns 3)" % cnt) 

473 return -1 

474 

475 cnt = RefCounter.get("/Z/*/?/\\", False) 

476 if cnt != 1: 476 ↛ 477line 476 didn't jump to line 477, because the condition on line 476 was never true

477 print("Error: count = %d != 1 after get (no ns 4)" % cnt) 

478 return -1 

479 

480 cnt = RefCounter.get("Z", False) 

481 if cnt != 2: 481 ↛ 482line 481 didn't jump to line 482, because the condition on line 481 was never true

482 print("Error: count = %d != 2 after get (no ns 1)" % cnt) 

483 return -1 

484 

485 cnt = RefCounter.get("Z/", False) 

486 if cnt != 2: 486 ↛ 487line 486 didn't jump to line 487, because the condition on line 486 was never true

487 print("Error: count = %d != 2 after get (no ns 2)" % cnt) 

488 return -1 

489 

490 cnt = RefCounter.get("/Z", False) 

491 if cnt != 2: 491 ↛ 492line 491 didn't jump to line 492, because the condition on line 491 was never true

492 print("Error: count = %d != 2 after get (no ns 3)" % cnt) 

493 return -1 

494 

495 cnt = RefCounter.get("/Z/*/?/\\", False) 

496 if cnt != 2: 496 ↛ 497line 496 didn't jump to line 497, because the condition on line 496 was never true

497 print("Error: count = %d != 2 after get (no ns 4)" % cnt) 

498 return -1 

499 

500 # resetAll 

501 RefCounter.resetAll("B") 

502 cnt = RefCounter.get("Z", False, "B") 

503 if cnt != 1: 503 ↛ 504line 503 didn't jump to line 504, because the condition on line 503 was never true

504 print("Error: count = %d != 1 after resetAll-get" % cnt) 

505 return -1 

506 

507 cnt = RefCounter.get("Z", False, "C") 

508 if cnt != 1: 508 ↛ 509line 508 didn't jump to line 509, because the condition on line 508 was never true

509 print("Error: count = %d != 1 after C.get" % cnt) 

510 return -1 

511 

512 RefCounter.resetAll("B") 

513 cnt = RefCounter.get("Z", False, "B") 

514 if cnt != 1: 514 ↛ 515line 514 didn't jump to line 515, because the condition on line 514 was never true

515 print("Error: count = %d != 1 after second resetAll-get" % cnt) 

516 return -1 

517 

518 cnt = RefCounter.get("Z", False, "C") 

519 if cnt != 2: 519 ↛ 520line 519 didn't jump to line 520, because the condition on line 519 was never true

520 print("Error: count = %d != 2 after second C.get" % cnt) 

521 return -1 

522 

523 RefCounter.resetAll("D") 

524 RefCounter.resetAll() 

525 cnt = RefCounter.put("Z", False, "B") 

526 if cnt != 0: 526 ↛ 527line 526 didn't jump to line 527, because the condition on line 526 was never true

527 print("Error: count = %d != 0 after resetAll-put" % cnt) 

528 return -1 

529 

530 cnt = RefCounter.put("Z", False, "C") 

531 if cnt != 0: 531 ↛ 532line 531 didn't jump to line 532, because the condition on line 531 was never true

532 print("Error: count = %d != 0 after C.resetAll-put" % cnt) 

533 return -1 

534 

535 RefCounter.resetAll() 

536 

537 return 0 

538 _runTests = staticmethod(_runTests) 

539 

540 

541if __name__ == '__main__': 541 ↛ 542line 541 didn't jump to line 542, because the condition on line 541 was never true

542 print("Running unit tests...") 

543 try: 

544 if RefCounter._runTests() == 0: 

545 print("All done, no errors") 

546 except RefCounterException as e: 

547 print("FAIL: Got exception: %s" % e) 

548 raise