Closed Bug 200632 Opened 22 years ago Closed 22 years ago

cookie rewrite, phase 3

Categories

(Core :: Networking: Cookies, defect)

defect
Not set
normal

Tracking

()

RESOLVED FIXED
mozilla1.5alpha

People

(Reporter: dwitte, Assigned: dwitte)

References

Details

Attachments

(5 files, 4 obsolete files)

okay! round three. Objectives: ----------- 1) merge nsCookies and nsCookieManager into nsCookieService (yay)! this means nsCookieService now implements nsICookieService, nsICookieManager, and nsICookieManager2. 2) improve mem efficiency of our base cookie storage class, and COMify it. while this may seem like an evil word, it's a "good thing" here, because we need it COMified for passing to the prompter and the UI. so doing it in our base class saves conversions and just makes things nicer. Notes: ------ a) making nsCookieService implement both the cookieservice and cookiemanager contracts introduces a slight complication. if nsICookieService and nsICookieManager have separate contractid's, then if you do_GetService both of them, you end up with two instances of nsCookieService, which is wrong. I asked bz about this and he suggested making the two contractid's the same; that is, we now have one contract that specifies we implement both the cookieservice and cookiemanager interfaces. since nsICookieManager is frozen, I'm not sure if I'm allowed to change its contractid - so instead I've changed (the unfrozen) nsICookieService's contractid to be the same as nsICookieManager's. I could use some feedback on this approach ;) b) our rewritten nsCookie class implements the frozen nsICookie (as before), but this interface slightly bites. so I've made a new interface, nsICookie2, that fixes the annoying mistakes. I haven't updated any consumers to use it yet, but that will come when we decide to attack wallet... c) I should explain the new nsCookie class. it contiguously allocates its member strings and stores ptrs to them, and hands them out as string types when required. we use flat strings for now, because some consumers require that (logging and writing-to-file). the class makes use of bitmasking, and also has a custom refcount impl (since we use a PRInt16 instead of PRInt32 refcount). so this class does a pretty good job with mem efficiency, though I have some ideas to make it better in future - perhaps when we implement arena allocation & placement new. d) oh, I merged nsCookiePrefObserver into nsCookieService too, since we really don't need it to be separate anymore. e) alecf, don't be upset at me for not using COMArray :) I stuck to nsVoidArray with manual addrefing and releasing, for two very good reasons. i) it's more convenient to store the cookies as a concrete nsCookie type rather than an nsICookie/nsICookie2 type: this is because nsCookie has some "fast" non-xpcom getters on it, for use in local code. and COMPtr's won't work with nsCookie because the cast to nsISupports is ambiguous. ii) when we switch to hashtables (very soon), we need to manually addref/release anyway, so we might as well start now. and we'll need to roll our own nsISimpleEnumerator then anyway, so there's no incentive to use COMArray's inbuilt one. ok, comments welcome please!
Attached patch baseline patch (deleted) — Splinter Review
I've split phase 3 up into a few parts, for reviewing convenience: a) a "baseline" patch, that makes no functional changes but simply moves the code from nsCookies and nsCookieManager into nsCookieService, renames functions, and shifts those horrible global vars (sCookieList, gCookiePrefObserver) into member vars. this patch is enormous and boring, because there are no changes of interest, so the idea is you can just ignore it. it's there for reference. b) the actual phase 3 patch for checkin. this is also very hard to read because it includes all the baseline stuff... c) a diffdiff between the actual patch and the "baseline". this only shows the changes of interest, so this one should be a lot easier to review. (note that ~1000 lines is just code movement from the pref observer, since it's now part of the cookieservice.)
Attached patch v1 complete patch (obsolete) (deleted) — Splinter Review
this is the full monty, part b.
Attached patch v1 diffdiff (wrt baseline) (obsolete) (deleted) — Splinter Review
the beast for review, part c.
Attachment #119424 - Flags: superreview?(darin)
Attachment #119424 - Flags: review?(alecf)
oh, one last note. there are a few questions in the code i'm not sure about, which i've marked with XXX comments. when you get around to reviewing, could you take a look at them and see what you think? (only the one's i've added, i.e. +'ed). thanks!
Status: NEW → ASSIGNED
Target Milestone: --- → mozilla1.4beta
Comment on attachment 119424 [details] [diff] [review] v1 diffdiff (wrt baseline) >+#include "nsWeakReference.h" // XXX required? if not, then remove it =) >+class nsCookie : public nsICookie2 ... >+ NS_IMETHOD QueryInterface(REFNSIID aIID, void** aInstancePtr); >+ NS_IMETHOD_(nsrefcnt) AddRef(void); >+ NS_IMETHOD_(nsrefcnt) Release(void); use NS_DECL_ISUPPORTS >+++ mozilla/extensions/cookie/nsCookie.cpp 2003-04-03 04:53:48.000000000 -0800 >+ // bitmask the bools, and pack them into one PRUint8 >+ mCookieFlags = ((aIsSession != PR_FALSE) << COOKIE_ISSESSION_BIT) | >+ ((aIsDomain != PR_FALSE) << COOKIE_ISDOMAIN_BIT ) | >+ ((aIsSecure != PR_FALSE) << COOKIE_ISSECURE_BIT ); >+ >+ // bitmask the two p3p flags, and pack them into one PRUint8. >+ // each flag needs 3 bits. >+ mP3PFlags = (aStatus << COOKIE_STATUS_BIT) | >+ (aPolicy << COOKIE_POLICY_BIT); > } what about using bit fields instead to avoid all this bit shifting? PRUint32 mIsSession : 1; PRUint32 mIsDomain : 1; PRUint32 mIsSecure : 1; PRUint32 mStatus : 4; PRUint32 mPolicy : 4; the compiler will create almost exactly the same code you have manually created with all the bit shifting.. and the compiler might even have ways of optimizing it further in some cases. >+// custom addref/release impl >+NS_IMETHODIMP_(nsrefcnt) nsCookie::AddRef(void) >+NS_IMETHODIMP_(nsrefcnt) nsCookie::Release(void) stock macros should work here.
Attachment #119424 - Flags: superreview?(darin) → superreview-
Attachment #119424 - Flags: review?(alecf)
Attached patch v2 complete patch (obsolete) (deleted) — Splinter Review
thanks for the amazingly fast review! learnt something new about bitfields today. nice stuff.
Attachment #119423 - Attachment is obsolete: true
Attachment #119424 - Attachment is obsolete: true
Attached patch v2 diffdiff (wrt baseline) (deleted) — Splinter Review
Attachment #119482 - Flags: superreview?(darin)
semicolon after NS_IMPL_ISUPPORTSX macro is not needed. more comments later...
Comment on attachment 119422 [details] [diff] [review] baseline patch sr=darin in order to have one class implement a pair of CID/COntractIDs (in this case the cookie manager and cookie service IDs), you should create a custom Constructor method instead of using NS_GENERIC_FACTORY_CONSTRUCTOR. NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR might be the right thing to use in this case or you could roll your own.
Attachment #119422 - Flags: superreview+
Comment on attachment 119482 [details] [diff] [review] v2 diffdiff (wrt baseline) >+ mPrefBranch = do_GetService(NS_PREFSERVICE_CONTRACTID, &rv); > if (NS_FAILED(rv)) return rv; does cookies really depend on prefs? or can it run without the pref service. i don't think it should have to be a fatal error to not have a pref service. >+ // cast the nsCookie to an nsICookie2. >+ // XXX is this valid - does the frozen nsICookieManager interface >+ // require that we hand these out as nsICookies, or can we assume >+ // the consumer will perform a QI (and _not_ a cast)? >+ nsICookie2 *cookieInList = NS_STATIC_CAST(nsICookie2*, NS_STATIC_CAST(nsCookie*, mCookieList.ElementAt(mCookieIndex++))); since nsCookie : nsICookie2 : nsICookie this is ok, but why not cast to nsICookie instead? otherwise, this patch looks great =) sr=darin with these issues addressed. also, please check to see who depends on nsCookie supporting weak reference. maybe it is just old baggage that we can do away with.
Attachment #119482 - Flags: superreview?(darin) → superreview+
Attached patch v3 complete patch (obsolete) (deleted) — Splinter Review
the full monty, part 3. obsoletes previous patches.
Attachment #119481 - Attachment is obsolete: true
Attachment #119482 - Attachment is obsolete: true
Attached patch v3 diffdiff (wrt v2) (deleted) — Splinter Review
okay, so this is becoming slightly ridiculous, but here goes... this is a diffdiff between v2 and v3 complete patches, so it shows the changes between those versions. addresses darin's comments (thanks!). notes: 1) removed weak refs from nsCookie.h. the only relevant code snippet I could find in our codesbase, was some usage of nsIMutableArray in nsCookiePromptService.cpp: nsCOMPtr<nsIMutableArray> objects; (...) rv = objects->AppendElement(aCookie, PR_FALSE); which explicitly declares strong refs... so <shrug> i have no idea why we ever had or currently need weak refs. poof. 2) backed out the contractid changes, so we have unique nsICookieService & nsICookieManager contractid's again. implemented the modulefactory portion as a singleton instead, per darin's suggestion, so we use stock NS_GENERIC_FACTORY_SINGLETON_CONSTRUCTOR along with two new functions, |nsCookieService::GetSingleton()| and |nsCookieService::FreeSingleton()|. most of the impl was taken from other examples in the codebase, so I'm not positive it's correct... a quick sanity check would be real nice. it does appear to work though. ;) 3) added a method to init prefs to their defaults, in case we can't get the prefservice. this removes the dependency on mPrefBranch so we no longer die if it's not available. (yes i know i could've just inited the prefs in the ctor, but i factored it into a function to keep the #ifdef MOZ_PHOENIXes in one place) 4) removed semicolons per darin's nit. ;) 5) fixed a minor list bug (sigh...) in RemoveExpiredCookies(). we need to include session cookies in the search for the oldest one. that's it! i'll carry over sr=darin and request r=alecf (though darin, if you could look at those modulefac changes, that'd be great). i spoke with darin and we decided that once this is in, we can merge cookies into necko (i.e. all dependencies on permissions code are failure-tolerant). which will give us a footprint & perf win because nsCookieHTTPNotify can die... yay! (not to mention we get to cvs remove nsCookies & nsCookieManager!)
Comment on attachment 120069 [details] [diff] [review] v3 complete patch carrying over sr=darin alecf: just to be clear... when you review this, you want to review the "v2 diffdiff (wrt baseline)" and then "v3 diffdiff (wrt v2)". don't look at the whole thing, it's really hard to review. the baseline & complete patches are there for reference (see comment 1 for why i split them up)
Attachment #120069 - Flags: superreview+
Attachment #120069 - Flags: review?(alecf)
Blocks: 201611
Attachment #120069 - Flags: review?(alecf)
Attached patch v3.1 complete patch (deleted) — Splinter Review
updated with a few improvements, comments to follow...
Attachment #120069 - Attachment is obsolete: true
Attached patch v3.1 diffdiff (wrt v3) (deleted) — Splinter Review
ok, here's a diffdiff of what changed between v3.1 and v3. man, these version-diffdiffs are becoming insane ;) explanations (in order of changes): 1) quieted some silly signed/unsigned compiler warnings (cookies is warning-free now). 2) removed a patch of dead code. this is live code in current trunk, but it's really not necessary (must be leftover cruft) because we deal with null aFirstURI in a graceful and correct manner. i must have missed deleting it at an earlier stage, sorry... 3) quieted a warning that we added in a while back - one of the cookie prefs is optional, so pretty much everyone was seeing the warning "error reading cookie prefs", which isn't good. so we just ignore the rv for that one pref. 4) changed the mailnews check in a subtle way - we now check currentURI if firstURI is null (previously we skipped all checks if firstURI was null). shouldn't really make a difference to anything, just makes slightly more sense. 5) fixed a glaring omission in CheckPath() - we weren't getting the path from the host before operating on it! that was stupid. (we didn't see this bug because it's a rarely, if never, executed codepath). other than that it's testing out well (the testsuite i just submitted is happy with it, and the singleton creation/destruction is working just fine). i'll re-request sr=darin because the changes here probably need looking at...
Attachment #120960 - Flags: superreview?(darin)
Attachment #120960 - Flags: review?(alecf)
maybe bracket this for readability: if (mCookiesDisabledForMailNews && + (aFirstURI && + IsFromMailNews(firstURIScheme) || IsFromMailNews(currentURIScheme))) { if (mCookiesDisabledForMailNews && + ((aFirstURI && IsFromMailNews(firstURIScheme)) || IsFromMailNews(currentURIScheme))) { otherwise the v3.1 diffdiff looks fine to me.
Comment on attachment 120960 [details] [diff] [review] v3.1 complete patch sr=darin
Attachment #120960 - Flags: superreview?(darin) → superreview+
alecf, darin: the v3.1 patch has a few important fixes that should probably ship with 1.4b (separate from the refactoring etc). since it hasn't gone in yet, what do you think would be best? i can either split out said fixes into a small patch against trunk, and get those into 1.4b - or, (more work but hopefully a little better) if we can get the full v3.1 patch reviewed and approved in the next few days, we could check the whole thing in. if you think drivers will have it ;) the latter option is fairly low-risk since the bulk of the patch is trivial code movement, and i've been testing it for a while now. it would also make the 1.4 branch a little easier to maintain (since it'll be our new stable branch when firebird comes along in 1.5).
revving milestone -> 1.5a.
Target Milestone: mozilla1.4beta → mozilla1.5alpha
Comment on attachment 119482 [details] [diff] [review] v2 diffdiff (wrt baseline) alecf said he might take a look at this soon, so... two comments: 1) i've since learned that declaring |inline foo();| in the header and then putting the fn body in the cpp is wrong - it won't get inlined (unless it's static, but that's another story). i do this quite a bit in nsCookieService.h. i'm not going to post a new patch to change that, but consider those bodies moved into the .h or otherwise uninlined. 2) the bitmasking in nsCookie may be overkill; i'll leave that to alecf's judgement. if i change the bitmasked bools into packedbools (and leave nsCookieStatus & nsCookiePolicy bitmasked as one byte), we increase sizeof(nsCookie) by 4 bytes. considering the overall sizeof a typical nsCookie is ~80 bytes, we're talking 5%, or 1k of 30k total (for 300 cookies). we use some of the bools (in particular mIsSession) frequently inside loops. the patches for review are "v2 diffdiff" and "v3 diffdiff". the "v3.1 diffdiff" is already in the tree, since we backported it. see comment 13.
Attachment #119482 - Attachment is obsolete: false
Comment on attachment 120960 [details] [diff] [review] v3.1 complete patch ok, finally starting to take a look at this.. regarding StrBlockCopy() - are you ready to switch to arenas now? :) + PRUint32 mIsSession : 1; + PRUint32 mIsDomain : 1; + PRUint32 mIsSecure : 1; + PRUint32 mStatus : 3; + PRUint32 mPolicy : 3; + PRUint32 mRefCnt : 16; maybe make mRefCnt:16 come first? I dunno, I just wonder if it might make a difference in case compilers do funny alignment? + } else if (!nsCRT::strcmp(aTopic, NS_PREFBRANCH_PREFCHANGE_TOPIC_ID)) { + // which pref changed? + NS_ConvertUCS2toUTF8 pref(aData); pref names are ASCII - really I need to document that better, but you can use NS_LossyConvertUCS2toASCII here the rest of this looks really good! sr=alecf - if you want to use arenas after all, let me know :)
Attachment #120960 - Flags: review?(alecf) → review+
oh neat, thanks alec! :) so I thought about arenas, but after asking a few folk I decided against it. for permissions it kinda made sense because the objects themselves were tiny and they were pretty much static. but here, cookies will be deleted pretty frequently - so do we really want to leak that stuff? if you have any ideas i didn't think of, do let me know. (i don't see how fixed size allocator would mesh well with the strings either) there may be some slight codesize bloat here due to the inlined nsCookie class members (notably nsDependentCString ctors and the bitmasking). i'll keep an eye on it after I check in, and i'll file a followup bug if things need attention.
checked in, with some changes to the #include sections (used a bunch of forward declarations instead), and removed the erroneous inline qualifiers. I also changed a few other occurrences of NS_ConvertUCS2toUTF8 in ::Observe methods per alecf's comment. codesize numbers for reference: + 354 on winnt beast +1328 on comet (2.96) + 469 on luna (3.2) so nothing major, but i'll play with it as time permits and see if I can refine things a little more.
Status: ASSIGNED → RESOLVED
Closed: 22 years ago
Resolution: --- → FIXED
So, um, did you notice that this caused a major leak increase on tinderbox? I filed bug 209571.
This caused bug 394243.
Depends on: 394243
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Created:
Updated:
Size: