Ns_ConnRunRequest in op.c does something like:

Ns_MutexLock(&ulock);
reqPtr = Ns_UrlSpecificGet(server, method, url, id);
...
Ns_MutexUnlock(&ulock);


Ns_UrlSpecificGet in urlspace.c does something like:

MkSeq(&seq, server, method, url);
Ns_MutexLock(&lock);
data = JunctionFind(&urlspace, seq, id, 0);
Ns_MutexUnlock(&lock);


i.e. there's double locking going on.  The second lock, in the
urlspace code, is under contention by all callers of urlspace
(requests, url2file, etc.), and many of these are very common
operations.


Users of urlspace need to call Ns_UrlSpecificAlloc() in their
initialisation code to get a magic ID.  This ID partitions the data of
each subsystem.  But the ID is stored within the 'Trie' and so needs
to be protected by the global lock.

What if instead the ID was used as in Thread Local Storage?  There's
an array of slots, where each slot contains a separate Trie, and the
ID is an index into this array.  Because ID's are allocated at start
up and aren't destroyed there need be no locking at run time to locate
the appropriate Trie for the caller.

The urlspace locking can now be removed because the callers locking
perfectly protects the Trie from concurrent access.  It would also
allow the caller to run lock-free in the case where all urlspace
entries are created at start up and only read at run time.


Does this make sense?

Reply via email to