First steps towards cookie jar thread-safety

* Change the semantics of the iterators copy constructor and assignment
operator: they now return a new iterator for the same cookie jar (and
same url for the UrlIterator). They don't try to point to the same
position as the copied iterator. The only purpose of these is to write
code such as:

Iterator it = jar.GetIterator();

so having a full copy isn't that useful.

* The per-domain cookie lists are now protected with a read-write lock.
The iterators retain a read lock while they are handling cookies from
that list. They get a write lock when doing Remove. Adding a cookie to
the jar also gets the write lock for the matching list

* Fix a memory leak when adding a new domain-list to the jar failed

* Simplify the declaration of the PrivateHashMap type (it would be
even simpler if HashMap was a public API)

* The domain hashmap is now a SynchronizedHashMap. It is locked as long
as an Iterator or UrlIterator exists, which may be a problem as these
are public APIs. Writing safe iterators for an hashmap with concurrent
accesses is not easy, so the API could be modified to return a list of
domains and a list of cookies for a given domain or URL instead. This
would suit the intended uses just as well.

* The jar now store const cookies, so there is no need to lock them for
access/modification. Updating a cookie is done by replacing it with
another one in the jar (with the same domain and value). There is still
the problem of deleting a cookie while other threads may still access
it, this will be fixed by making cookies BReferenceable.
This commit is contained in:
Adrien Destugues
2014-06-11 12:59:33 +02:00
parent 9aec6561a8
commit 463ffbfde4
4 changed files with 288 additions and 113 deletions
+31 -15
View File
@@ -5,16 +5,28 @@
#ifndef _B_NETWORK_COOKIE_JAR_H_
#define _B_NETWORK_COOKIE_JAR_H_
#include <pthread.h>
#include <Archivable.h>
#include <Flattenable.h>
#include <Message.h>
#include <ObjectList.h>
#include <NetworkCookie.h>
#include <ObjectList.h>
#include <String.h>
#include <Url.h>
typedef BObjectList<BNetworkCookie> BNetworkCookieList;
class BNetworkCookieList: public BObjectList<const BNetworkCookie> {
public:
BNetworkCookieList();
~BNetworkCookieList();
status_t LockForReading();
status_t LockForWriting();
status_t Unlock();
private:
pthread_rwlock_t fLock;
};
class BNetworkCookieJar : public BArchivable, public BFlattenable {
@@ -79,18 +91,19 @@ private:
class BNetworkCookieJar::Iterator {
public:
Iterator(const Iterator& other);
Iterator(const BNetworkCookieJar* map);
~Iterator();
bool HasNext() const;
BNetworkCookie* Next();
BNetworkCookie* NextDomain();
BNetworkCookie* Remove();
void RemoveDomain();
Iterator& operator=(const Iterator& other);
bool HasNext() const;
const BNetworkCookie* Next();
const BNetworkCookie* NextDomain();
const BNetworkCookie* Remove();
void RemoveDomain();
private:
Iterator(const BNetworkCookieJar* map);
Iterator(const Iterator& other);
void _FindNext();
@@ -101,26 +114,29 @@ private:
PrivateIterator* fIterator;
BNetworkCookieList* fLastList;
BNetworkCookieList* fList;
BNetworkCookie* fElement;
BNetworkCookie* fLastElement;
const BNetworkCookie* fElement;
const BNetworkCookie* fLastElement;
int32 fIndex;
};
// The copy constructor and assignment operator create new iterators for the
// same cookie jar and url. Iteration will start over.
class BNetworkCookieJar::UrlIterator {
public:
UrlIterator(const UrlIterator& other);
~UrlIterator();
bool HasNext() const;
BNetworkCookie* Next();
BNetworkCookie* Remove();
const BNetworkCookie* Next();
const BNetworkCookie* Remove();
UrlIterator& operator=(const UrlIterator& other);
private:
UrlIterator(const BNetworkCookieJar* map,
const BUrl& url);
void _Initialize();
bool _SuperDomain();
void _FindNext();
void _FindDomain();
@@ -133,8 +149,8 @@ private:
PrivateIterator* fIterator;
BNetworkCookieList* fList;
BNetworkCookieList* fLastList;
BNetworkCookie* fElement;
BNetworkCookie* fLastElement;
const BNetworkCookie* fElement;
const BNetworkCookie* fLastElement;
int32 fIndex;
int32 fLastIndex;