Closed bevis-tseng closed 8 years ago
Ah crap. Yeah, you're right. Hm........ what would the users want here? This is a bit of an edge case so I'm not sure how often this would get hit, but we definitely need to figure out what to do.
Options:
@inexorabletash, @cmumford, @sicking for thoughts
Actually, I think we can solve this in the following way:
The transaction that is given back is scheduled in the NEXT available spot in the queue, after all exclusive lock (write) transactions have finished. This will push back any another transactions that are waiting for an exclusive lock on any of the transaction's object stores.
So in the example above, the transaction B will not be scheduled until after C is finished.
Does that make sense?
So in the example above, the transaction B will not be scheduled until after C is finished.
So, do we still apply the rule of invoking ObserverCallback per-transaction basis without bundle the changes together and have 2 readonly transactions (let's say 'post-B txn', 'post-C txn') created in sequence but are delivered to the callback in the same order until txn C is finished?
If yes, it makes sense to me!
I think so, yes, as long as you forgot a 'not' in that sentence:
So, do we still apply the rule of invoking ObserverCallback per-transaction basis without bundle the changes together and have 2 readonly transactions (let's say 'post-B txn', 'post-C txn') created in sequence but are NOT delivered to the callback in the same order until txn C is finished?
Scenario clarification:
Hm.... I'm going to check w/ people to make sure that would be OK
Hey @arthurhsu, would this mess you guys up? Or is this OK expected behavior.
If not, then we need to:
@nolanlawson Can you PTAL at this issue? What would you expect/want in this scenario?
In chrome, we can actually have the step 7 above have the transaction WITHOUT C's changes, as leveldb let's us grab a snapshot of the world from the B transaction (as in the end everything is writen serially in a log database). So this isn't a problem for us, but it might be for FF.
What's the behavior of Transaction A w.r.t. the callbacks made from B and C? Transaction A sees the changes of B and C, and it decided to commit, what will be happening?
@arthurhsu so transaction A already committed, sorry, that was just the transaction that we start the observer with. I could have read the world state in for the observer, pretend it read in some of X, Y, and Z.
Ok, so I think we have the following options/behaviors:
WDYT? That's all I can think of right now. @aliams can you also look at this?
For 2, the accumulation is tricky and I'm not sure how this will scale if there's a half-baked transaction happening in between B and C and install another observer.
For 4 we still need to know B/C is changing DB so A can know to read XYZ after B/C committed. This seems to be back to square 0.
I think 1 and 3 can be accommodated by Lovefield since our onChange event can deal either.
I think so, yes, as long as you forgot a 'not' in that sentence:
Yes, I forgot a 'not' here. :|
FWIW this case should not affect PouchDB. We have no readwrite operations that can be parallelized; we always update the same stores.
@daleharvey may want to comment on whether or not this would affect our upcoming "idb-next" adapter. (Speaking of which, Observers seems like a killer feature for idb-next.)
@bevis-tseng and @aliams, What do you think about option 1 above? Where we only include the object stores in the observer transaction if they were modified?
For option#1, there is no concern from implementation perspective. My concern is that whether this change meets or limits any real use cases that devs want.
@daleharvey, does option #1 (the transaction given to the observer only includes object stores that were modified, not necessarily all object stores it's observing) conflict w/ your feature?
I'll find a Docs contact to weigh in as well.
I think Option 1 does not meet some use cases.
Consider for example the UI in github which shows the list of participants in this issue.
It would observe two objectStores: A) It would observe an objectStore which caches metadata about individual issues, one entry per issue. The entries have a property which lists the participants github-user-ids B) It would observe an objectStore which caches icons for github users keyed on github user id.
Changes to either store might result in the list of participants UI needing to be updated. If a participant is added/removed, you need to update the list. Likewise if the picture used by a participant is updated.
If you get a transaction which only contains either of the two stores, you won't be able to update he UI.
Another way to think of this is that any time that you are observing multiple objectStores in order to do a "join" between them, you need a transaction which spans all those object stores. Using such joins is likely generally the reason to observe multiple stores.
There is also the following two options:
5) State that two transactions are only parallelizable if they don't have overlapping scopes and there is no observers which have scopes which overlap both transactions. 6) Same as option 3, but for implementations that aren't able to keep a snapshot, require that the implementation don't parallelize the two transactions.
Note that parallelizing non-overlapping transactions is not something that implementations are required to do. So option 6 is essentially the same as option 3 from a normative point of view.
Hm. Yeah, I think option 6 gives the most flexibility for implementation, and also keeps the use cases you mentioned above non-complex.
@bevis-tseng, how about option 6 there?
If my understanding is correct that option#6 will apply option#5 if snapshot is not supported by the implementation, then it's true that it will be more flexible for implementation.
The docs folks said they don't mind. I think I'm going to shoot for option 6 from Jonas unless anyone has strong objections.
this also eliminates the ambiguity issue brought up in #33 about option#1, which is nice.
There is a design issue to provide a read-only transaction immediately to the IDBObserverCallback in the following scenario:
[1] http://w3c.github.io/IndexedDB/#transaction-lifetime-concept