I'm saying that an async API is overkill and unwieldy if all you need is WorkerLocalStorage.<div><br></div><div>If you're going to route your localstorage access through an async API anyway, then you might as well proxy it to the parent page - there's very little advantage to doing it otherwise, other than access to lexically scoped resources from within your callback.</div>
<div><br></div><div>But, yeah, if you want to provide access to shared worker/page storage, then an async API would be the way to go - I'm just saying that if you don't actually need shared storage, then you could maintain a more convenient synchronous silo'd API.</div>
<div><br></div><div>Since Jeremy didn't really elaborate on the use case, and he's getting feedback from app developers that I'm not privy to, I figured I'd ask him.</div><div><br></div><div>-atw<br><br><div class="gmail_quote">
On Wed, Sep 16, 2009 at 11:34 AM, Michael Nordman <span dir="ltr"><<a href="mailto:michaeln@google.com">michaeln@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex;">
<br><br><div class="gmail_quote"><div class="im">On Wed, Sep 16, 2009 at 11:24 AM, James Robinson <span dir="ltr"><<a href="mailto:jamesr@google.com" target="_blank">jamesr@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div class="gmail_quote"><div>On Wed, Sep 16, 2009 at 10:53 AM, Michael Nordman <span dir="ltr"><<a href="mailto:michaeln@google.com" target="_blank">michaeln@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<br><br><div class="gmail_quote"><div>On Wed, Sep 16, 2009 at 9:58 AM, Drew Wilson <span dir="ltr"><<a href="mailto:atwilson@google.com" target="_blank">atwilson@google.com</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
Jeremy, what's the use case here - do developers want workers to have access to shared local storage with pages? Or do they just want workers to have access to their own non-shared local storage?<div><br></div><div>Because we could just give workers their own separate WorkerLocalStorage and let them have at it. A worker could block all the other accesses to WorkerLocalStorage within that domain, but so be it - it wouldn't affect page access, and we already had that issue with the (now removed?) synchronous SQL API.<br>
<br></div><div>I think a much better case can be made for WorkerLocalStorage than for "give workers access to page LocalStorage", and the design issues are much simpler.</div></blockquote><div><br></div></div><div>
Putting workers in their own storage silo doesn't really make much sense? Sure it may be simpler for browser vendors, but does that make life simpler for app developers, or just have them scratching their heads about how to read/write the same data set from either flavor of context in their application?</div>
<div><br></div><div>I see no rhyme or reason for the arbitrary barrier except for browser vendors to work around the awkward implict locks on LocalStorage (the source of much grief). Consider this... would it make sense to cordon off the databases workers vs pages can see? I would think not, and i would hope others agree.</div>
</div></blockquote><div><br></div></div><div>The difference is that the database interface is purely asynchronous whereas storage is synchronous.</div></div></blockquote><div><br></div></div><div>Sure... we're talking about adding an async api that allows worker to access a local storage repository... should such a thing exist, why should it not provide access to the same repository as seen by pages?</div>
<div><div></div><div class="h5">
<div><br></div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="gmail_quote"><div><br></div><div>If multiple threads have synchronous access to the same shared resource then there has to be a consistency model. ECMAScript does not provide for one so it has to be done at a higher level. Since there was not a solution in the first versions that shipped, the awkward implicit locks you mention were suggested as a workaround. However it's far from clear that these solve the problem and are implementable. It seems like the only logical continuation of this path would be to add explicit, blocking synchronization primitives for developers to deal with - which I think everyone agrees would be a terrible idea. If you're worried about developers scratching their heads about how to pass data between workers just think about happens-before relationships and multi-threaded memory models.</div>
<div><br></div><div>In a hypothetical world without synchronous access to LocalStorage/cookies from workers, there is no shared memory between threads except via message passing. This can seem a bit tricky for developers but is very easy to reason about and prove correctness and the absence of deadlocks.</div>
<div><br></div><font color="#888888"><div>- James</div></font><div><div></div><div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="gmail_quote">
<div><div></div><div>
<div><br></div><div> </div><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div><br></div><div>-atw</div><div><div></div><div><div><br>
<div class="gmail_quote">On Tue, Sep 15, 2009 at 8:27 PM, Jonas Sicking <span dir="ltr"><jonas@sicking.cc></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
<div>On Tue, Sep 15, 2009 at 6:56 PM, Jeremy Orlow <<a href="mailto:jorlow@chromium.org" target="_blank">jorlow@chromium.org</a>> wrote:<br>
> One possible solution is to add an asynchronous callback interface for<br>
> LocalStorage into workers. For example:<br>
> function myCallback(localStorage) {<br>
> localStorage.accountBalance = localStorage.accountBalance + 100;<br>
> }<br>
> executeLocalStorageCallback(myCallback); // TODO: Make this name better<br>
> :-)<br>
> The interface is simple. You can only access localStorage via a callback.<br>
> Any use outside of the callback is illegal and would raise an exception.<br>
> The callback would acquire the storage mutex during execution, but the<br>
> worker's execution would not block during this time. Of course, it's still<br>
> possible for a poorly behaving worker to do large amounts of computation in<br>
> the callback, but hopefully the fact they're executing in a callback makes<br>
> the developer more aware of the problem.<br>
<br>
</div>First off, I agree that not having localStorage in workers is a big<br>
problem that we need to address.<br>
<br>
If I were designing the localStorage interface today I would use the<br>
above interface that you suggest. Grabbing localStorage can only be<br>
done asynchronously, and while you're using it, no one else can get a<br>
reference to it. This way there are no race conditions, but also no<br>
way for anyone to have to lock.<br>
<br>
So one solution is to do that in parallel to the current localStorage<br>
interface. Let's say we introduce a 'clientStorage' object. You can<br>
only get a reference to it using a 'getClientStorage' function. This<br>
function is available both to workers and windows. The storage is<br>
separate from localStorage so no need to worry about the 'storage<br>
mutex'.<br>
<br>
There is of course a risk that a worker grabs on to the clientStorage<br>
and holds it indefinitely. This would result in the main window (or<br>
another worker) never getting a reference to it. However it doesn't<br>
affect responsiveness of that window, it's just that the callback will<br>
never happen. While that's not ideal, it seems like a smaller problem<br>
than any other solution that I can think of. And the WebDatabase<br>
interfaces are suffering from the same problem if I understand things<br>
correctly.<br>
<br>
There's a couple of other interesting things we could expose on top of this:<br>
<br>
First, a synchronous API for workers. We could allow workers to<br>
synchronously get a reference to clientStorage. If someone is<br>
currently using clientStorage then the worker blocks until the storage<br>
becomes available. We could either use a callback as the above, which<br>
blocks until the clientStorage is acquired and only holds the storage<br>
until the callback exists. Or we could expose clientStorage as a<br>
property which holds the storage until control is returned to the<br>
worker eventloop, or until some explicit release API is called. The<br>
latter would be how localStorage is now defined, with the important<br>
difference that localStorage exposes the synchronous API to windows.<br>
<br>
Second, allow several named storage areas. We could add an API like<br>
getNamedClientStorage(name, callback). This would allow two different<br>
workers to simultaneously store things in a storage areas, as long as<br>
they don't need to use the *same* storage area. It would also allow a<br>
worker and the main window to simultaneously use separate storage<br>
areas.<br>
<br>
However we need to be careful if we add both above features. We can't<br>
allow a worker to grab multiple storage areas at the same time since<br>
that could cause deadlocks. However with proper APIs I believe we can<br>
avoid that.<br>
<font color="#888888"><br>
/ Jonas<br>
</font></blockquote></div><br></div>
</div></div></blockquote></div></div></div><br>
</blockquote></div></div></div><br>
</blockquote></div></div></div><br>
</blockquote></div><br></div>