/srv/irclogs.ubuntu.com/2013/05/20/#launchpad-dev.txt

wgrantStevenK: That's going to issue several queries for each filter03:21
StevenKwgrant: I'm not sure I can do it in one query given the number of tables involved04:01
StevenKwgrant: But suggestions welcome04:04
StevenKwgrant: DB patch with ON DELETE CASCADE?04:11
wgrantStevenK: I'd add a batch filter deletion method04:11
StevenKwgrant: So you're okay with multiple queries, say 4, but not 4 * number of filters ?04:14
wgrantStevenK: Right, a constant number of queries is necessary04:15
wgrantYou can't sensibly do less than one per table.04:15
wgrantBut one per table per filter is excessive and banned.04:15
StevenKwgrant: http://pastebin.ubuntu.com/5682621/04:28
wgrantStevenK: I'd replace the list comp and helper method with a for loop04:30
wgrantAnd you can hopefully kill off BSF.delete() now04:30
wgrantOr at least reimplement it in terms of the deleteMultiple04:30
wgrantIf you can't remove it entirely04:30
StevenKwgrant: http://pastebin.ubuntu.com/5682645/04:41
wgrantStevenK: Right04:42
StevenKwgrant: The MP has updated04:48
wgrantStevenK: What about the structsub deletion behaviour in BSF.delete()? That was probably a misfeature, but it may need to be replaced.04:56
StevenKwgrant: No tests fail with it removed04:57
StevenKAnd I agree about it being a misfeature04:58
StevenKWell, bin/test -vvt structuralsubscription doesn't show any failures04:59
wgrantStevenK: No tests fail, but does the UI work?04:59
wgrantThe code appears to implement an invariant that there's always a filter for every structsub05:00
wgrantIt implements it racily, but it's still likely that something depends on it05:00
StevenKwgrant: I can create a structsub05:01
StevenKAnd change the filter05:01
StevenKAnd delete both filters and create a new one05:03
StevenK(Using Person:+structural-subscriptions)05:03
wgrantStevenK: Yeah, but we'd have the odd behaviour that you could have a sub without a filter, which probably does nothing05:10
StevenKwgrant: The UI actually copes with that.05:11
StevenKLaunchpad05:11
StevenKBug mail is not filtered; mail for Foo Bar about Launchpad will always be sent.05:11
StevenKCreate a new filter05:12
StevenKwgrant: http://people.canonical.com/~stevenk/structsub.jpg05:16
wgrantStevenK: But does the UI lie?05:20
wgrantthat's probably from the migration; I'm not sure if the backend will actually cope05:21
wgrantAIUI it just looks for matching BSFs05:21
StevenKwgrant: The Launchpad structsub was created by me05:21
StevenKThe other two are from sampledata05:21
wgrantStevenK: How did you create it?05:21
StevenKProduct:+subscribe05:21
wgrantAnd you didn't manually delete the BSF?05:22
StevenKI did, but via Person:+structural-subscriptions05:22
wgrantRight, so have you tested how the backend handles it?05:22
wgrantI suspect that that UI code is just a leftover from the migration when not everything had a BSF yet05:23
StevenKwgrant: Person:+structural-subscriptions was written for structsubs only, +subscriptions is the legacy stuff05:23
wgrant+structural-subscriptions is legacy05:23
wgrant+subscriptions is not legacy05:23
wgrant+s-s predates BSF05:24
wgrantSo it is not a valid argument for anything05:25
wgrant(structsubs date back to '07 or so; it's just BugSubscriptionFilter and co that are new)05:25
StevenKwgrant: If I resurrect _has_other_filters, to restore the old behaviour, I can't move delete to using deleteMultiple, since deleteMultiple makes a choice at the end if it removes itself, or its parent structsub05:32
wgrantStevenK: We first need to establish what the model invariants must be05:33
wgrantThen we can work out implementation of deletion05:33
StevenKwgrant: http://pastebin.ubuntu.com/5682717/05:38
wgrantStevenK: Possibly, but I'd prefer to discover what the model constraints actually are05:41
StevenKwgrant: I've been trying to work out which code determines if a notification will be sent based on filtering to see if it will gracefully cope with no filters, but I'm having trouble finding it05:46
wgrantStevenK: Let me see05:48
wgrantI hadn't noticed before, but it's actually more careful than any other LP code to be non-racy05:48
wgrantSo it seems to be pretty serious about maintaining that invariant.05:48
wgrant    source = IStore(StructuralSubscription).using(05:50
wgrant        StructuralSubscription,05:50
wgrant        Join(BugSubscriptionFilter,05:50
wgrant             BugSubscriptionFilter.structural_subscription_id ==05:50
wgrant             StructuralSubscription.id),05:50
wgrantQED05:50
StevenKAh, then there is UI bug too05:51
StevenKThe filter page allows you to delete the last filter05:51
StevenKMaybe that's okay since it will destroy the structsub too05:51
wgrantStevenK: Right, that's fine, because that's handled at the model level05:52
wgrantThat's the whole point of the code I'm questioning the removal of05:52
StevenKwgrant: Then my resurrection that I pasted should be fine06:00
wgrantStevenK: Sort of.06:00
wgrantStevenK: It's an extremely confusing interface06:00
wgrantAnd very likely to go wrong06:00
wgrantOh, also it doesn't actually do anything06:01
StevenKwgrant: Oh?06:02
StevenKWell, delete doesn't have to call into deleteMultiple06:02
wgrantStevenK: deleteMultiple deletes all BSFs, then if delete_self then it deletes all BSFs.06:03
StevenKwgrant: Not exactly. The filters aren't deleted, the internals are06:04
wgrantStevenK: Oh, I see, I misunderstood06:05
wgrantThat's still O(len(filters)) queries06:05
wgrant=> fail06:05
StevenKwgrant: How?06:05
StevenKWe loop over the kinds, not the filters06:06
wgrantBSF.delete06:06
wgrantCalls deleteMultiple for each BSF06:06
wgrantThen checks for each BSF that there are other BSFs06:06
wgrantThen if not it deletes the structsub06:06
StevenKwgrant: Right. But deleting the structsub calls deleteMultiple directly06:07
wgrantStevenK: This seems extremely convoluted. I'd probably have a method which deletes BSFs, then deletes any corresponding SSs if they have 0 BSFs.06:09
wgrantSimple06:09
wgrantFoolproof06:09
wgrantFast06:09
wgrantShort06:09
wgrantSo the same as BSF.delete is today, except operating over more than one BSF06:09
StevenKwgrant: Right, and then delete calls that. Do I need to call _has_other_filters for locking?06:10
wgrantYou'll want to do the same sort of locking, yes06:11
wgrantAnd Storm doesn't have support for SELECT FOR UPDATE, so you'll probably have to use SQL or define a Select derivative.06:11
StevenKwgrant: Bah, now I'm having trouble crafting a query to find the structsubs with no filters06:21
wgrantStevenK: SELECT * FROM structuralsubscription WHERE NOT EXISTS (SELECT 1 FROM bugsubscriptionfilter WHERE bugsubscriptionfilter.structuralsubscription = structuralsubscription.id) FOR UPDATE;06:24
wgrantWith an added ID constraint to ask for just the structsubs that you've changed06:24
wgrantNo, not quite06:24
wgrantWon't take enough of a lock06:24
wgrantInvert the NOT EXISTS06:25
StevenKI'm currently locking BSF only, currently06:25
wgrantThen do set difference in Python06:25
wgrantThat's useless06:25
wgrantBSF isn't the table that we want to lock06:25
wgrantAlso, this SELECT FOR UPDATE stuff will probably fail in pg9.306:25
wgrantAh, no, it will work06:26
wgrantBecause of the backward compat changes that they made late.06:26
StevenKwgrant: http://pastebin.ubuntu.com/5682802/ I'm on the right track?06:28
wgrantStevenK: That sort of thing06:38
wgrantHowever06:38
wgrantI've just realised that the original code isn't as safe as it thinks it is.06:39
StevenKwgrant: If can change that SELECT FOR UPDATE to return id rather than *?06:45
wgrantStevenK: That won't affect the locking.06:46
wgrantIt still won't do what the author expected.06:46
StevenKwgrant: Even the query you pasted above?06:47
wgrantStevenK: Even that query.06:48
wgrantDo you understand what it tries to do?06:48
StevenKIt tries to lock all structsub rows given a bunch of filter ids06:48
wgrantYes, but to what end?06:50
StevenKSo they don't change under us?06:50
wgrantNot quite06:51
StevenKwgrant: What then?06:52
wgrantStevenK: It is trying to block multiple concurrent BSF.delete()s for the same SS06:52
wgrantNot to prevent an FK violation06:52
wgrantBut to prevent two concurrent deletions from deleting the last two BSFs for an SS, with neither transaction noticing that it's the last.06:52
=== tasdomas_afk is now known as tasdomas
wgrantExcept that, because the SS row isn't actually being updated, the transactions can run concurrently as long as one commits before the other does the SELECT FOR UPDATE.06:53
wgrantSo it fails to prevent the race06:54
StevenKwgrant: So what can we do instead?06:57
wgrantStevenK: I think the only completely safe method is to do an actual UPDATE, even if it changes nothing07:04
wgrantOr we could update the UI to say that something with no filters does nothing07:04
wgrantAnd then get garbo to prune them daily07:04
wgrantI don't think there's another way to obtain a lock before the snapshot is frozen.07:06
wgrantYeah, that shouldn't be possible, because you'd need a snapshot to find the tuples that you need to lock07:07
wgrantSo you can't obtain the lock before snapshotting07:07
wgrantOh07:17
wgrantOr we just select the BSFs for SHARE07:17
wgrantAnd of course I totally misread the code because it uses UPDATE when it actually wants SHARE.07:20
wgrantSo it is safe.07:20
wgrantStevenK: SELECT id FROM structuralsubscription WHERE id IN (4) AND EXISTS (SELECT 1 FROM bugsubscriptionfilter WHERE bugsubscriptionfilter.structuralsubscription = structuralsubscription.id FOR SHARE);07:25
wgrantThe FOR SHARE in the subquery will prevent a concurrent transaction from updating or deleting the BSFs that we use as evidence for keeping the SS07:26
StevenKwgrant: Ah, but you're missing one thing -- we have the BSF ids, not the SS ids.07:39
wgrantStevenK: It is not a huge issue to obtain the SS IDs07:40
=== Ursinha-afk is now known as Ursinha
=== wedgwood_away is now known as wedgwood
=== tasdomas is now known as tasdomas_afk
=== Ursinha_ is now known as Ursinha
=== Ursinha is now known as Ursinha-afk
=== Ursinha-afk is now known as Ursinha
=== cinerama_ is now known as cinerama
StevenKwgrant: http://pastebin.ubuntu.com/5685381/ Branch from yesterday, against -r submit: for readability23:24
wgrantStevenK: I'd grab the IDs from the FOR SHARE query, and use them to exclude SSs from deletion, rather than reselecting them potentially differently. Also, you shouldn't be using sqlvalues any more.23:44
wgrantOtherwise I think that's good23:45
wgrantI've got to run out for a few hours now; will be back lunchish.23:45
=== wedgwood is now known as wedgwood_away

Generated by irclog2html.py 2.7 by Marius Gedminas - find it at mg.pov.lt!