Re: [IndexedDB] Implicit transactions
On Fri, Aug 6, 2010 at 1:56 PM, Jeremy Orlow jor...@chromium.org wrote: On Thu, Aug 5, 2010 at 8:56 PM, Jonas Sicking jo...@sicking.cc wrote: Ok, I'm going to start by taking a step back here. There is no such thing as implicit transactions. db.objectStore(foo, mode) is just syntactic sugar for db.transaction([foo], mode).objectStore(foo) so it always starts a new transaction. I think for now, lets take db.objectStore(..) out of the discussion and focus on how we want db.transaction() to work. In the end we may or may not want to keep db.objectStore() if it causes too much confusion. One thing that we have to first realize is that every IDBObjectStore instance is tied to a specific transaction. This is required to avoid ambiguity in what transaction a request is made against. Consider the following code trans1 = db.transaction([foo, bar], READ_WRITE); trans2 = db.transaction([foo, students], READ_ONLY); os1 = trans1.objectStore(foo); os2 = trans2.objectStore(foo); alert(os1 === os2); os1.get(someKey).onsuccess = ...; In this code, the alert will always display false. The os1 and os2 are two distinct objects. They have to be, otherwise we wouldn't know which transaction to place the get() request against. Once a transaction has been committed or aborted, using any of the IDBObjectStore objects connected with it will throw an error. So the example mentioned earlier in the thread (i'll use different syntax than used previously in the thread): var gMyos = null; function fun1() { gMyos = db.transaction([foo]).objectStore(foo); gMyos.get(someKey).onsuccess = ...; } function fun2() { gMyos.get(someOtherKey); } If we return to the main even loop between calling fun1 and fun2, the .get() call in fun2 will *always* throw. IMHO it's a good thing that this consistently throws. Consider also function fun3() { var trans = db.transaction([foo, bar], READ_WRITE); trans.objectStore(bar).openCursor(...).onsuccess = ...; } It would IMHO be a bad thing if calling fun3 right before calling fun2 all of a sudden made fun2 not throw and instead place a request against the transaction created in fun3. While I definitely think it can be confusing that there are several IDBObjectStore instances referring to the same underlying objectStore, I think this is ultimately a good thing as it reduces the risk of accidentally placing a request against the wrong transaction. It means that in order to place a request against a transaction, you must either have a reference to that transaction, or a reference to an objectStore retrieved from that transaction. Another way to think of it is this. You generally don't place requests against an objectStore or index. You place them against a transaction. By tying IDBObjectStores to a given transaction, it's always explicit which transaction you are using. On Thu, Aug 5, 2010 at 3:04 AM, Jeremy Orlow jor...@chromium.org wrote: On Wed, Aug 4, 2010 at 7:47 PM, Shawn Wilsher sdwi...@mozilla.com wrote: On 8/4/2010 10:53 AM, Jeremy Orlow wrote: Whoatransaction() is synchronous?!? Ok, so I guess the entire premise of my question was super confused. :-) It is certainly spec'd that way [1]. The locks do not get acquired until the first actual bit of work is done though. I fully understand how the trick works. I just didn't comprehend the fact that the Mozilla proposal (what's now in the spec) was removing any way to get into an IDBTransactionEvent handler besides doing an initial data access. I wouldn't have agreed to the proposal had I realized this. Lets say I had the following bit of initialization code in my program: var myDB = ... var myObjectStore = myDB.objectStore(someObjectStore); var myIndex = myObjectStore.index(someIndex); var anotherObjectStore = myDB.objectStore(anotherObjectStore); As described above, grabbing references like this is not what you want to do. If we were to allow this I think we would run a severe risk of making it very hard to understand which transaction you are placing requests against. And then I wanted to start a transaction that'd access some key and then presumably do some other work. As currently specced, here's what I'd need to do: myDB.transaction().objectStore(someObjectStore).index(someIndex).get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); vs doing something like this: myDB.asyncTransaction().onsuccess(function() { myIndex.get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); }); With the former, we actually have more typing and the code is harder to read. Sure, when I'm writing short code snipits, the synchronous form can be more convenient and readable, but forcing this upon every situation is going to be a hinderance. Please, lets add back in a transaction method that returns an
Re: [IndexedDB] Implicit transactions
On Fri, Aug 6, 2010 at 1:56 PM, Jeremy Orlow jor...@chromium.org wrote: On Thu, Aug 5, 2010 at 8:56 PM, Jonas Sicking jo...@sicking.cc wrote: Ok, I'm going to start by taking a step back here. There is no such thing as implicit transactions. db.objectStore(foo, mode) is just syntactic sugar for db.transaction([foo], mode).objectStore(foo) so it always starts a new transaction. I think for now, lets take db.objectStore(..) out of the discussion and focus on how we want db.transaction() to work. In the end we may or may not want to keep db.objectStore() if it causes too much confusion. One thing that we have to first realize is that every IDBObjectStore instance is tied to a specific transaction. This is required to avoid ambiguity in what transaction a request is made against. Consider the following code trans1 = db.transaction([foo, bar], READ_WRITE); trans2 = db.transaction([foo, students], READ_ONLY); os1 = trans1.objectStore(foo); os2 = trans2.objectStore(foo); alert(os1 === os2); os1.get(someKey).onsuccess = ...; In this code, the alert will always display false. The os1 and os2 are two distinct objects. They have to be, otherwise we wouldn't know which transaction to place the get() request against. Once a transaction has been committed or aborted, using any of the IDBObjectStore objects connected with it will throw an error. So the example mentioned earlier in the thread (i'll use different syntax than used previously in the thread): var gMyos = null; function fun1() { gMyos = db.transaction([foo]).objectStore(foo); gMyos.get(someKey).onsuccess = ...; } function fun2() { gMyos.get(someOtherKey); } If we return to the main even loop between calling fun1 and fun2, the .get() call in fun2 will *always* throw. IMHO it's a good thing that this consistently throws. Consider also function fun3() { var trans = db.transaction([foo, bar], READ_WRITE); trans.objectStore(bar).openCursor(...).onsuccess = ...; } It would IMHO be a bad thing if calling fun3 right before calling fun2 all of a sudden made fun2 not throw and instead place a request against the transaction created in fun3. While I definitely think it can be confusing that there are several IDBObjectStore instances referring to the same underlying objectStore, I think this is ultimately a good thing as it reduces the risk of accidentally placing a request against the wrong transaction. It means that in order to place a request against a transaction, you must either have a reference to that transaction, or a reference to an objectStore retrieved from that transaction. Another way to think of it is this. You generally don't place requests against an objectStore or index. You place them against a transaction. By tying IDBObjectStores to a given transaction, it's always explicit which transaction you are using. On Thu, Aug 5, 2010 at 3:04 AM, Jeremy Orlow jor...@chromium.org wrote: On Wed, Aug 4, 2010 at 7:47 PM, Shawn Wilsher sdwi...@mozilla.com wrote: On 8/4/2010 10:53 AM, Jeremy Orlow wrote: Whoatransaction() is synchronous?!? Ok, so I guess the entire premise of my question was super confused. :-) It is certainly spec'd that way [1]. The locks do not get acquired until the first actual bit of work is done though. I fully understand how the trick works. I just didn't comprehend the fact that the Mozilla proposal (what's now in the spec) was removing any way to get into an IDBTransactionEvent handler besides doing an initial data access. I wouldn't have agreed to the proposal had I realized this. Lets say I had the following bit of initialization code in my program: var myDB = ... var myObjectStore = myDB.objectStore(someObjectStore); var myIndex = myObjectStore.index(someIndex); var anotherObjectStore = myDB.objectStore(anotherObjectStore); As described above, grabbing references like this is not what you want to do. If we were to allow this I think we would run a severe risk of making it very hard to understand which transaction you are placing requests against. And then I wanted to start a transaction that'd access some key and then presumably do some other work. As currently specced, here's what I'd need to do: myDB.transaction().objectStore(someObjectStore).index(someIndex).get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); vs doing something like this: myDB.asyncTransaction().onsuccess(function() { myIndex.get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); }); With the former, we actually have more typing and the code is harder to read. Sure, when I'm writing short code snipits, the synchronous form can be more convenient and readable, but forcing this upon every situation is going to be a hinderance. Please, lets add back in a transaction method that returns
Re: [IndexedDB] Implicit transactions
On Fri, Aug 6, 2010 at 6:52 AM, Jeremy Orlow jor...@chromium.org wrote: On Fri, Aug 6, 2010 at 1:56 PM, Jeremy Orlow jor...@chromium.org wrote: On Thu, Aug 5, 2010 at 8:56 PM, Jonas Sicking jo...@sicking.cc wrote: Ok, I'm going to start by taking a step back here. There is no such thing as implicit transactions. db.objectStore(foo, mode) is just syntactic sugar for db.transaction([foo], mode).objectStore(foo) so it always starts a new transaction. I think for now, lets take db.objectStore(..) out of the discussion and focus on how we want db.transaction() to work. In the end we may or may not want to keep db.objectStore() if it causes too much confusion. One thing that we have to first realize is that every IDBObjectStore instance is tied to a specific transaction. This is required to avoid ambiguity in what transaction a request is made against. Consider the following code trans1 = db.transaction([foo, bar], READ_WRITE); trans2 = db.transaction([foo, students], READ_ONLY); os1 = trans1.objectStore(foo); os2 = trans2.objectStore(foo); alert(os1 === os2); os1.get(someKey).onsuccess = ...; In this code, the alert will always display false. The os1 and os2 are two distinct objects. They have to be, otherwise we wouldn't know which transaction to place the get() request against. Once a transaction has been committed or aborted, using any of the IDBObjectStore objects connected with it will throw an error. So the example mentioned earlier in the thread (i'll use different syntax than used previously in the thread): var gMyos = null; function fun1() { gMyos = db.transaction([foo]).objectStore(foo); gMyos.get(someKey).onsuccess = ...; } function fun2() { gMyos.get(someOtherKey); } If we return to the main even loop between calling fun1 and fun2, the .get() call in fun2 will *always* throw. IMHO it's a good thing that this consistently throws. Consider also function fun3() { var trans = db.transaction([foo, bar], READ_WRITE); trans.objectStore(bar).openCursor(...).onsuccess = ...; } It would IMHO be a bad thing if calling fun3 right before calling fun2 all of a sudden made fun2 not throw and instead place a request against the transaction created in fun3. While I definitely think it can be confusing that there are several IDBObjectStore instances referring to the same underlying objectStore, I think this is ultimately a good thing as it reduces the risk of accidentally placing a request against the wrong transaction. It means that in order to place a request against a transaction, you must either have a reference to that transaction, or a reference to an objectStore retrieved from that transaction. Another way to think of it is this. You generally don't place requests against an objectStore or index. You place them against a transaction. By tying IDBObjectStores to a given transaction, it's always explicit which transaction you are using. On Thu, Aug 5, 2010 at 3:04 AM, Jeremy Orlow jor...@chromium.org wrote: On Wed, Aug 4, 2010 at 7:47 PM, Shawn Wilsher sdwi...@mozilla.com wrote: On 8/4/2010 10:53 AM, Jeremy Orlow wrote: Whoatransaction() is synchronous?!? Ok, so I guess the entire premise of my question was super confused. :-) It is certainly spec'd that way [1]. The locks do not get acquired until the first actual bit of work is done though. I fully understand how the trick works. I just didn't comprehend the fact that the Mozilla proposal (what's now in the spec) was removing any way to get into an IDBTransactionEvent handler besides doing an initial data access. I wouldn't have agreed to the proposal had I realized this. Lets say I had the following bit of initialization code in my program: var myDB = ... var myObjectStore = myDB.objectStore(someObjectStore); var myIndex = myObjectStore.index(someIndex); var anotherObjectStore = myDB.objectStore(anotherObjectStore); As described above, grabbing references like this is not what you want to do. If we were to allow this I think we would run a severe risk of making it very hard to understand which transaction you are placing requests against. And then I wanted to start a transaction that'd access some key and then presumably do some other work. As currently specced, here's what I'd need to do: myDB.transaction().objectStore(someObjectStore).index(someIndex).get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); vs doing something like this: myDB.asyncTransaction().onsuccess(function() { myIndex.get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); }); With the former, we actually have more typing and the code is harder to read. Sure, when I'm writing short code snipits, the synchronous form can be more convenient and readable, but forcing this upon every situation is going to
Re: [IndexedDB] Implicit transactions
On Fri, Aug 6, 2010 at 4:04 PM, Jonas Sicking jo...@sicking.cc wrote: On Fri, Aug 6, 2010 at 6:52 AM, Jeremy Orlow jor...@chromium.org wrote: On Fri, Aug 6, 2010 at 1:56 PM, Jeremy Orlow jor...@chromium.org wrote: On Thu, Aug 5, 2010 at 8:56 PM, Jonas Sicking jo...@sicking.cc wrote: Ok, I'm going to start by taking a step back here. There is no such thing as implicit transactions. db.objectStore(foo, mode) is just syntactic sugar for db.transaction([foo], mode).objectStore(foo) so it always starts a new transaction. I think for now, lets take db.objectStore(..) out of the discussion and focus on how we want db.transaction() to work. In the end we may or may not want to keep db.objectStore() if it causes too much confusion. One thing that we have to first realize is that every IDBObjectStore instance is tied to a specific transaction. This is required to avoid ambiguity in what transaction a request is made against. Consider the following code trans1 = db.transaction([foo, bar], READ_WRITE); trans2 = db.transaction([foo, students], READ_ONLY); os1 = trans1.objectStore(foo); os2 = trans2.objectStore(foo); alert(os1 === os2); os1.get(someKey).onsuccess = ...; In this code, the alert will always display false. The os1 and os2 are two distinct objects. They have to be, otherwise we wouldn't know which transaction to place the get() request against. Once a transaction has been committed or aborted, using any of the IDBObjectStore objects connected with it will throw an error. So the example mentioned earlier in the thread (i'll use different syntax than used previously in the thread): var gMyos = null; function fun1() { gMyos = db.transaction([foo]).objectStore(foo); gMyos.get(someKey).onsuccess = ...; } function fun2() { gMyos.get(someOtherKey); } If we return to the main even loop between calling fun1 and fun2, the .get() call in fun2 will *always* throw. IMHO it's a good thing that this consistently throws. Consider also function fun3() { var trans = db.transaction([foo, bar], READ_WRITE); trans.objectStore(bar).openCursor(...).onsuccess = ...; } It would IMHO be a bad thing if calling fun3 right before calling fun2 all of a sudden made fun2 not throw and instead place a request against the transaction created in fun3. While I definitely think it can be confusing that there are several IDBObjectStore instances referring to the same underlying objectStore, I think this is ultimately a good thing as it reduces the risk of accidentally placing a request against the wrong transaction. It means that in order to place a request against a transaction, you must either have a reference to that transaction, or a reference to an objectStore retrieved from that transaction. Another way to think of it is this. You generally don't place requests against an objectStore or index. You place them against a transaction. By tying IDBObjectStores to a given transaction, it's always explicit which transaction you are using. On Thu, Aug 5, 2010 at 3:04 AM, Jeremy Orlow jor...@chromium.org wrote: On Wed, Aug 4, 2010 at 7:47 PM, Shawn Wilsher sdwi...@mozilla.com wrote: On 8/4/2010 10:53 AM, Jeremy Orlow wrote: Whoatransaction() is synchronous?!? Ok, so I guess the entire premise of my question was super confused. :-) It is certainly spec'd that way [1]. The locks do not get acquired until the first actual bit of work is done though. I fully understand how the trick works. I just didn't comprehend the fact that the Mozilla proposal (what's now in the spec) was removing any way to get into an IDBTransactionEvent handler besides doing an initial data access. I wouldn't have agreed to the proposal had I realized this. Lets say I had the following bit of initialization code in my program: var myDB = ... var myObjectStore = myDB.objectStore(someObjectStore); var myIndex = myObjectStore.index(someIndex); var anotherObjectStore = myDB.objectStore(anotherObjectStore); As described above, grabbing references like this is not what you want to do. If we were to allow this I think we would run a severe risk of making it very hard to understand which transaction you are placing requests against. And then I wanted to start a transaction that'd access some key and then presumably do some other work. As currently specced, here's what I'd need to do: myDB.transaction().objectStore(someObjectStore).index(someIndex).get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); vs doing something like this: myDB.asyncTransaction().onsuccess(function() { myIndex.get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); }); With the former, we actually have more
Re: [IndexedDB] Implicit transactions
On Fri, Aug 6, 2010 at 8:06 AM, Jeremy Orlow jor...@chromium.org wrote: On Fri, Aug 6, 2010 at 4:04 PM, Jonas Sicking jo...@sicking.cc wrote: On Fri, Aug 6, 2010 at 6:52 AM, Jeremy Orlow jor...@chromium.org wrote: On Fri, Aug 6, 2010 at 1:56 PM, Jeremy Orlow jor...@chromium.org wrote: On Thu, Aug 5, 2010 at 8:56 PM, Jonas Sicking jo...@sicking.cc wrote: Ok, I'm going to start by taking a step back here. There is no such thing as implicit transactions. db.objectStore(foo, mode) is just syntactic sugar for db.transaction([foo], mode).objectStore(foo) so it always starts a new transaction. I think for now, lets take db.objectStore(..) out of the discussion and focus on how we want db.transaction() to work. In the end we may or may not want to keep db.objectStore() if it causes too much confusion. One thing that we have to first realize is that every IDBObjectStore instance is tied to a specific transaction. This is required to avoid ambiguity in what transaction a request is made against. Consider the following code trans1 = db.transaction([foo, bar], READ_WRITE); trans2 = db.transaction([foo, students], READ_ONLY); os1 = trans1.objectStore(foo); os2 = trans2.objectStore(foo); alert(os1 === os2); os1.get(someKey).onsuccess = ...; In this code, the alert will always display false. The os1 and os2 are two distinct objects. They have to be, otherwise we wouldn't know which transaction to place the get() request against. Once a transaction has been committed or aborted, using any of the IDBObjectStore objects connected with it will throw an error. So the example mentioned earlier in the thread (i'll use different syntax than used previously in the thread): var gMyos = null; function fun1() { gMyos = db.transaction([foo]).objectStore(foo); gMyos.get(someKey).onsuccess = ...; } function fun2() { gMyos.get(someOtherKey); } If we return to the main even loop between calling fun1 and fun2, the .get() call in fun2 will *always* throw. IMHO it's a good thing that this consistently throws. Consider also function fun3() { var trans = db.transaction([foo, bar], READ_WRITE); trans.objectStore(bar).openCursor(...).onsuccess = ...; } It would IMHO be a bad thing if calling fun3 right before calling fun2 all of a sudden made fun2 not throw and instead place a request against the transaction created in fun3. While I definitely think it can be confusing that there are several IDBObjectStore instances referring to the same underlying objectStore, I think this is ultimately a good thing as it reduces the risk of accidentally placing a request against the wrong transaction. It means that in order to place a request against a transaction, you must either have a reference to that transaction, or a reference to an objectStore retrieved from that transaction. Another way to think of it is this. You generally don't place requests against an objectStore or index. You place them against a transaction. By tying IDBObjectStores to a given transaction, it's always explicit which transaction you are using. On Thu, Aug 5, 2010 at 3:04 AM, Jeremy Orlow jor...@chromium.org wrote: On Wed, Aug 4, 2010 at 7:47 PM, Shawn Wilsher sdwi...@mozilla.com wrote: On 8/4/2010 10:53 AM, Jeremy Orlow wrote: Whoatransaction() is synchronous?!? Ok, so I guess the entire premise of my question was super confused. :-) It is certainly spec'd that way [1]. The locks do not get acquired until the first actual bit of work is done though. I fully understand how the trick works. I just didn't comprehend the fact that the Mozilla proposal (what's now in the spec) was removing any way to get into an IDBTransactionEvent handler besides doing an initial data access. I wouldn't have agreed to the proposal had I realized this. Lets say I had the following bit of initialization code in my program: var myDB = ... var myObjectStore = myDB.objectStore(someObjectStore); var myIndex = myObjectStore.index(someIndex); var anotherObjectStore = myDB.objectStore(anotherObjectStore); As described above, grabbing references like this is not what you want to do. If we were to allow this I think we would run a severe risk of making it very hard to understand which transaction you are placing requests against. And then I wanted to start a transaction that'd access some key and then presumably do some other work. As currently specced, here's what I'd need to do: myDB.transaction().objectStore(someObjectStore).index(someIndex).get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); vs doing something like this: myDB.asyncTransaction().onsuccess(function() { myIndex.get(someKey).onsuccess(function() {
Re: [IndexedDB] Implicit transactions
On Wed, Aug 4, 2010 at 7:47 PM, Shawn Wilsher sdwi...@mozilla.com wrote: On 8/4/2010 10:53 AM, Jeremy Orlow wrote: Whoatransaction() is synchronous?!? Ok, so I guess the entire premise of my question was super confused. :-) It is certainly spec'd that way [1]. The locks do not get acquired until the first actual bit of work is done though. I fully understand how the trick works. I just didn't comprehend the fact that the Mozilla proposal (what's now in the spec) was removing any way to get into an IDBTransactionEvent handler besides doing an initial data access. I wouldn't have agreed to the proposal had I realized this. Lets say I had the following bit of initialization code in my program: var myDB = ... var myObjectStore = myDB.objectStore(someObjectStore); var myIndex = myObjectStore.index(someIndex); var anotherObjectStore = myDB.objectStore(anotherObjectStore); And then I wanted to start a transaction that'd access some key and then presumably do some other work. As currently specced, here's what I'd need to do: myDB.transaction().objectStore(someObjectStore).index(someIndex).get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); vs doing something like this: myDB.asyncTransaction().onsuccess(function() { myIndex.get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); }); With the former, we actually have more typing and the code is harder to read. Sure, when I'm writing short code snipits, the synchronous form can be more convenient and readable, but forcing this upon every situation is going to be a hinderance. Please, lets add back in a transaction method that returns an IDBRequest. J
Re: [IndexedDB] Implicit transactions
Ok, I'm going to start by taking a step back here. There is no such thing as implicit transactions. db.objectStore(foo, mode) is just syntactic sugar for db.transaction([foo], mode).objectStore(foo) so it always starts a new transaction. I think for now, lets take db.objectStore(..) out of the discussion and focus on how we want db.transaction() to work. In the end we may or may not want to keep db.objectStore() if it causes too much confusion. One thing that we have to first realize is that every IDBObjectStore instance is tied to a specific transaction. This is required to avoid ambiguity in what transaction a request is made against. Consider the following code trans1 = db.transaction([foo, bar], READ_WRITE); trans2 = db.transaction([foo, students], READ_ONLY); os1 = trans1.objectStore(foo); os2 = trans2.objectStore(foo); alert(os1 === os2); os1.get(someKey).onsuccess = ...; In this code, the alert will always display false. The os1 and os2 are two distinct objects. They have to be, otherwise we wouldn't know which transaction to place the get() request against. Once a transaction has been committed or aborted, using any of the IDBObjectStore objects connected with it will throw an error. So the example mentioned earlier in the thread (i'll use different syntax than used previously in the thread): var gMyos = null; function fun1() { gMyos = db.transaction([foo]).objectStore(foo); gMyos.get(someKey).onsuccess = ...; } function fun2() { gMyos.get(someOtherKey); } If we return to the main even loop between calling fun1 and fun2, the .get() call in fun2 will *always* throw. IMHO it's a good thing that this consistently throws. Consider also function fun3() { var trans = db.transaction([foo, bar], READ_WRITE); trans.objectStore(bar).openCursor(...).onsuccess = ...; } It would IMHO be a bad thing if calling fun3 right before calling fun2 all of a sudden made fun2 not throw and instead place a request against the transaction created in fun3. While I definitely think it can be confusing that there are several IDBObjectStore instances referring to the same underlying objectStore, I think this is ultimately a good thing as it reduces the risk of accidentally placing a request against the wrong transaction. It means that in order to place a request against a transaction, you must either have a reference to that transaction, or a reference to an objectStore retrieved from that transaction. Another way to think of it is this. You generally don't place requests against an objectStore or index. You place them against a transaction. By tying IDBObjectStores to a given transaction, it's always explicit which transaction you are using. On Thu, Aug 5, 2010 at 3:04 AM, Jeremy Orlow jor...@chromium.org wrote: On Wed, Aug 4, 2010 at 7:47 PM, Shawn Wilsher sdwi...@mozilla.com wrote: On 8/4/2010 10:53 AM, Jeremy Orlow wrote: Whoatransaction() is synchronous?!? Ok, so I guess the entire premise of my question was super confused. :-) It is certainly spec'd that way [1]. The locks do not get acquired until the first actual bit of work is done though. I fully understand how the trick works. I just didn't comprehend the fact that the Mozilla proposal (what's now in the spec) was removing any way to get into an IDBTransactionEvent handler besides doing an initial data access. I wouldn't have agreed to the proposal had I realized this. Lets say I had the following bit of initialization code in my program: var myDB = ... var myObjectStore = myDB.objectStore(someObjectStore); var myIndex = myObjectStore.index(someIndex); var anotherObjectStore = myDB.objectStore(anotherObjectStore); As described above, grabbing references like this is not what you want to do. If we were to allow this I think we would run a severe risk of making it very hard to understand which transaction you are placing requests against. And then I wanted to start a transaction that'd access some key and then presumably do some other work. As currently specced, here's what I'd need to do: myDB.transaction().objectStore(someObjectStore).index(someIndex).get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); vs doing something like this: myDB.asyncTransaction().onsuccess(function() { myIndex.get(someKey).onsuccess(function() { anotherObjectStore.get(someOtherKey).onsuccess(...); }); }); With the former, we actually have more typing and the code is harder to read. Sure, when I'm writing short code snipits, the synchronous form can be more convenient and readable, but forcing this upon every situation is going to be a hinderance. Please, lets add back in a transaction method that returns an IDBRequest. The current design of the spec is that which IDBObjectStore you place a request against determines which transaction you are using. It sounds to me like you want a design where each IDBObjectStore instance represents just a objectStore
Re: [IndexedDB] Implicit transactions
On Wed, Aug 4, 2010 at 4:42 PM, Jeremy Orlow jor...@chromium.org wrote: In the IndexedDB spec, there are two ways to create a transaction. One is explicit (by calling IDBDatabase.transaction()) and one is implicit (for example, by calling IDBDatabase.objectStore.get(someKey)). I have questions about the latter, but before bringing these up, I think it might be best to give a bit of background (as I understand it) to make sure we're all on the same page: Belief 1: No matter how the transaction is started, any subsequent calls done within an IDBTransactionEvent (which is the event fired for almost every IDBRequest.onsuccess call since almost all of them are for operations done within the context of a transaction) will continue running in the same transaction. So, for example, the following code will atomically increment a counter: myDB.transaction().onsuccess(function() { myDB.objectStore(someObjectStore).get(counter).onsuccess(function() { myDB.objectStore(someObjectStore).put(counter, event.result + 1); }); }); Belief 2: Let's say I ran the following code: myDB.transaction().onsuccess(function() { window.myObjectStore = myDB.objectStore(someObjectStore); /* do some other work */ }); And then at any point later in the program (after that first transaction had committed) I could do the following: myDB.transaction().onsuccess(function() { window.myObjectStore.get(some value).onsuccess(...); }); Even though myObjectStore was originally fetched during some other transaction, it's quite clear that I'm accessing values from that object store in this new transaction's context, and thus that's exactly what happens and this is allowed. I think it's only allowed as long as the object store in question is in the scope of this other transaction. Implicitly created transactions: At a high level, the intent is for IDBDatabase.objectStore.get(someKey).onsuccess(...); to just work, even when not called in an IDBTransactionEvent handler. But what happens if I run the following code (outside of an IDBTransactionEvent handler): for (var i=0; i5; ++i) myDB.objectStore(someObjectStore).get(someKey).onsuccess(...); Do we want that to create 5 separate transactions or 5 requests within the same transaction? As currently specced, I think that would indeed start 5 separate transactions. But couldn't you save the object store in a variable before the loop? And what if we run my earlier example (that stored an object store to window.myObjectStore within a transaction we started explicitly) and then run the following code (outside of an IDBTransactionEventHandler): window.myObjectStore.get(someKey).onsuccess(...); myDB.objectStore(someObjectStore).get(someKey).onsuccess(...) Should both be legal? Will this create one or two transactions? I think simply calling window.myObjectStore.get() would not create a transaction. I think it would just throw? myDB.objectStore().get() would create a transaction. Speccing such transactions: After thinking about this, I only see a couple options for how to spec implicitly created transactions: When an operation that needs to be done in a transaction (i.e. anything that touches data) is done outside of an IDBTransactionEvent handler... 1) that operation will be done in its own, newly created transaction. 2) if there already exists an implicitly created transaction for that objectStore, it'll be done in that transaction. Otherwise a new one will be created. 3) if there already exists _any_ transaction with access to that objectStore, it'll be done in that transaction. Otherwise a new one will be created. 2 seems like it'd match the users intention in a lot of cases, but its biggest problem is that it's non-deterministic. If you do one .get() and then set a time out and do another, you don't know whether they'll be in the same transaction or not. That's right, it seems like a problem to me. 3 seems to have the same problem except it's even less predictable. So, but process of elimination, it seems as though 1 is our only option in terms of how to spec this. Or am I missing something? Well, what's wrong with what's specced today: - you can only call get/put/etc in the context of a transaction. If you don't, they'll throw. - in the context of a transaction means in a transaction callback or after you created an implicit transaction and until control returns to the main browser event loop. Read-only by default too? Another somewhat related question: should implicitly created transactions be read-only (which is the default for explicitly created ones)? If so, that means that we expect the following to fail: myDB.objectStore(someObjectStore).get(counter).onsuccess(function() { myDB.objectStore(someObjectStore).put(counter, event.result + 1); }); Unfortunately, it seems as though a lot of use cases for implicitly created transactions would involve more than just reads. But if we
Re: [IndexedDB] Implicit transactions
On Wed, Aug 4, 2010 at 5:26 PM, Andrei Popescu andr...@google.com wrote: On Wed, Aug 4, 2010 at 4:42 PM, Jeremy Orlow jor...@chromium.org wrote: In the IndexedDB spec, there are two ways to create a transaction. One is explicit (by calling IDBDatabase.transaction()) and one is implicit (for example, by calling IDBDatabase.objectStore.get(someKey)). I have questions about the latter, but before bringing these up, I think it might be best to give a bit of background (as I understand it) to make sure we're all on the same page: Belief 1: No matter how the transaction is started, any subsequent calls done within an IDBTransactionEvent (which is the event fired for almost every IDBRequest.onsuccess call since almost all of them are for operations done within the context of a transaction) will continue running in the same transaction. So, for example, the following code will atomically increment a counter: myDB.transaction().onsuccess(function() { myDB.objectStore(someObjectStore).get(counter).onsuccess(function() { myDB.objectStore(someObjectStore).put(counter, event.result + 1); }); }); Belief 2: Let's say I ran the following code: myDB.transaction().onsuccess(function() { window.myObjectStore = myDB.objectStore(someObjectStore); /* do some other work */ }); And then at any point later in the program (after that first transaction had committed) I could do the following: myDB.transaction().onsuccess(function() { window.myObjectStore.get(some value).onsuccess(...); }); Even though myObjectStore was originally fetched during some other transaction, it's quite clear that I'm accessing values from that object store in this new transaction's context, and thus that's exactly what happens and this is allowed. I think it's only allowed as long as the object store in question is in the scope of this other transaction. Of course. (I should have explicitly mentioned that though.) Implicitly created transactions: At a high level, the intent is for IDBDatabase.objectStore.get(someKey).onsuccess(...); to just work, even when not called in an IDBTransactionEvent handler. But what happens if I run the following code (outside of an IDBTransactionEvent handler): for (var i=0; i5; ++i) myDB.objectStore(someObjectStore).get(someKey).onsuccess(...); Do we want that to create 5 separate transactions or 5 requests within the same transaction? As currently specced, I think that would indeed start 5 separate transactions. But couldn't you save the object store in a variable before the loop? To be clear, you're suggesting that the following would result in 1 transaction? var myOS = myDB.objectStore(someObjectStore); for (var i=0; i5; ++i) myOS.get(someKey).onsuccess(...); This would seem to imply that, when used outside of an IDBTransactionEvent context, each instance of an objectStore object will be linked to its own transaction? I'd assume that any children (for example IDBIndex objects) that come from that IDBObjectStore would also be linked to the same transaction? What about the following: var myOS = myDB.objectStore(someObjectStore); myOS.get(someKey).onsuccess(...); /* do other stuff for a while...onsuccess above fired and thus the implicitly created transaction was committed implicitly */ myOS.get(anotherKey).onsuccess(...); The implicitly created transaction has completed before the second .get() call. Would the second call throw or would it start another implicit transaction? And what if we run my earlier example (that stored an object store to window.myObjectStore within a transaction we started explicitly) and then run the following code (outside of an IDBTransactionEventHandler): window.myObjectStore.get(someKey).onsuccess(...); myDB.objectStore(someObjectStore).get(someKey).onsuccess(...) Should both be legal? Will this create one or two transactions? I think simply calling window.myObjectStore.get() would not create a transaction. I think it would just throw? myDB.objectStore().get() would create a transaction. If the second .get in my last example would fail (i.e. ObjectStores are somehow bound to a transaction, and once that transaction finishes, it cannot be used outside of an IDBTransactionEvent context), then I could see this making sense. Otherwise could you please explain why this is? Speccing such transactions: After thinking about this, I only see a couple options for how to spec implicitly created transactions: When an operation that needs to be done in a transaction (i.e. anything that touches data) is done outside of an IDBTransactionEvent handler... 1) that operation will be done in its own, newly created transaction. 2) if there already exists an implicitly created transaction for that objectStore, it'll be done in that transaction. Otherwise a new one will be created. 3) if there already exists _any_ transaction
Re: [IndexedDB] Implicit transactions
On Wed, Aug 4, 2010 at 5:46 PM, Jeremy Orlow jor...@chromium.org wrote: On Wed, Aug 4, 2010 at 5:26 PM, Andrei Popescu andr...@google.com wrote: On Wed, Aug 4, 2010 at 4:42 PM, Jeremy Orlow jor...@chromium.org wrote: In the IndexedDB spec, there are two ways to create a transaction. One is explicit (by calling IDBDatabase.transaction()) and one is implicit (for example, by calling IDBDatabase.objectStore.get(someKey)). I have questions about the latter, but before bringing these up, I think it might be best to give a bit of background (as I understand it) to make sure we're all on the same page: Belief 1: No matter how the transaction is started, any subsequent calls done within an IDBTransactionEvent (which is the event fired for almost every IDBRequest.onsuccess call since almost all of them are for operations done within the context of a transaction) will continue running in the same transaction. So, for example, the following code will atomically increment a counter: myDB.transaction().onsuccess(function() { myDB.objectStore(someObjectStore).get(counter).onsuccess(function() { myDB.objectStore(someObjectStore).put(counter, event.result + 1); }); }); Belief 2: Let's say I ran the following code: myDB.transaction().onsuccess(function() { window.myObjectStore = myDB.objectStore(someObjectStore); /* do some other work */ }); And then at any point later in the program (after that first transaction had committed) I could do the following: myDB.transaction().onsuccess(function() { window.myObjectStore.get(some value).onsuccess(...); }); Even though myObjectStore was originally fetched during some other transaction, it's quite clear that I'm accessing values from that object store in this new transaction's context, and thus that's exactly what happens and this is allowed. I think it's only allowed as long as the object store in question is in the scope of this other transaction. Of course. (I should have explicitly mentioned that though.) Implicitly created transactions: At a high level, the intent is for IDBDatabase.objectStore.get(someKey).onsuccess(...); to just work, even when not called in an IDBTransactionEvent handler. But what happens if I run the following code (outside of an IDBTransactionEvent handler): for (var i=0; i5; ++i) myDB.objectStore(someObjectStore).get(someKey).onsuccess(...); Do we want that to create 5 separate transactions or 5 requests within the same transaction? As currently specced, I think that would indeed start 5 separate transactions. But couldn't you save the object store in a variable before the loop? To be clear, you're suggesting that the following would result in 1 transaction? var myOS = myDB.objectStore(someObjectStore); for (var i=0; i5; ++i) myOS.get(someKey).onsuccess(...); This would seem to imply that, when used outside of an IDBTransactionEvent context, each instance of an objectStore object will be linked to its own transaction? I'd assume that any children (for example IDBIndex objects) that come from that IDBObjectStore would also be linked to the same transaction? That's my understanding, yes. What about the following: var myOS = myDB.objectStore(someObjectStore); myOS.get(someKey).onsuccess(...); /* do other stuff for a while...onsuccess above fired and thus the implicitly created transaction was committed implicitly */ myOS.get(anotherKey).onsuccess(...); The implicitly created transaction has completed before the second .get() call. Would the second call throw or would it start another implicit transaction? My understanding is that it would throw. And what if we run my earlier example (that stored an object store to window.myObjectStore within a transaction we started explicitly) and then run the following code (outside of an IDBTransactionEventHandler): window.myObjectStore.get(someKey).onsuccess(...); myDB.objectStore(someObjectStore).get(someKey).onsuccess(...) Should both be legal? Will this create one or two transactions? I think simply calling window.myObjectStore.get() would not create a transaction. I think it would just throw? myDB.objectStore().get() would create a transaction. If the second .get in my last example would fail (i.e. ObjectStores are somehow bound to a transaction, and once that transaction finishes, it cannot be used outside of an IDBTransactionEvent context), then I could see this making sense. Otherwise could you please explain why this is? Yes, it would throw as that object store is no longer in the scope of any transaction. Speccing such transactions: After thinking about this, I only see a couple options for how to spec implicitly created transactions: When an operation that needs to be done in a transaction (i.e. anything that touches data) is done outside of an IDBTransactionEvent handler... 1) that
Re: [IndexedDB] Implicit transactions
I talked to Andrei in person. He seemed to think this was discussed and agreed upon sometime earlier but agreed the spec could be more clear. On Wed, Aug 4, 2010 at 5:46 PM, Jeremy Orlow jor...@chromium.org wrote: On Wed, Aug 4, 2010 at 5:26 PM, Andrei Popescu andr...@google.com wrote: On Wed, Aug 4, 2010 at 4:42 PM, Jeremy Orlow jor...@chromium.org wrote: In the IndexedDB spec, there are two ways to create a transaction. One is explicit (by calling IDBDatabase.transaction()) and one is implicit (for example, by calling IDBDatabase.objectStore.get(someKey)). I have questions about the latter, but before bringing these up, I think it might be best to give a bit of background (as I understand it) to make sure we're all on the same page: Belief 1: No matter how the transaction is started, any subsequent calls done within an IDBTransactionEvent (which is the event fired for almost every IDBRequest.onsuccess call since almost all of them are for operations done within the context of a transaction) will continue running in the same transaction. So, for example, the following code will atomically increment a counter: myDB.transaction().onsuccess(function() { myDB.objectStore(someObjectStore).get(counter).onsuccess(function() { myDB.objectStore(someObjectStore).put(counter, event.result + 1); }); }); Belief 2: Let's say I ran the following code: myDB.transaction().onsuccess(function() { window.myObjectStore = myDB.objectStore(someObjectStore); /* do some other work */ }); And then at any point later in the program (after that first transaction had committed) I could do the following: myDB.transaction().onsuccess(function() { window.myObjectStore.get(some value).onsuccess(...); }); Even though myObjectStore was originally fetched during some other transaction, it's quite clear that I'm accessing values from that object store in this new transaction's context, and thus that's exactly what happens and this is allowed. I think it's only allowed as long as the object store in question is in the scope of this other transaction. Of course. (I should have explicitly mentioned that though.) Implicitly created transactions: At a high level, the intent is for IDBDatabase.objectStore.get(someKey).onsuccess(...); to just work, even when not called in an IDBTransactionEvent handler. But what happens if I run the following code (outside of an IDBTransactionEvent handler): for (var i=0; i5; ++i) myDB.objectStore(someObjectStore).get(someKey).onsuccess(...); Do we want that to create 5 separate transactions or 5 requests within the same transaction? As currently specced, I think that would indeed start 5 separate transactions. But couldn't you save the object store in a variable before the loop? To be clear, you're suggesting that the following would result in 1 transaction? var myOS = myDB.objectStore(someObjectStore); for (var i=0; i5; ++i) myOS.get(someKey).onsuccess(...); This would seem to imply that, when used outside of an IDBTransactionEvent context, each instance of an objectStore object will be linked to its own transaction? I'd assume that any children (for example IDBIndex objects) that come from that IDBObjectStore would also be linked to the same transaction? What about the following: var myOS = myDB.objectStore(someObjectStore); myOS.get(someKey).onsuccess(...); /* do other stuff for a while...onsuccess above fired and thus the implicitly created transaction was committed implicitly */ myOS.get(anotherKey).onsuccess(...); The implicitly created transaction has completed before the second .get() call. Would the second call throw or would it start another implicit transaction? Andrei said the second .get (assuming the code is not literal...since there's no way an onsuccess could fire unless we returned control to JavaScript) should not fire. And what if we run my earlier example (that stored an object store to window.myObjectStore within a transaction we started explicitly) and then run the following code (outside of an IDBTransactionEventHandler): window.myObjectStore.get(someKey).onsuccess(...); myDB.objectStore(someObjectStore).get(someKey).onsuccess(...) Should both be legal? Will this create one or two transactions? I think simply calling window.myObjectStore.get() would not create a transaction. I think it would just throw? myDB.objectStore().get() would create a transaction. If the second .get in my last example would fail (i.e. ObjectStores are somehow bound to a transaction, and once that transaction finishes, it cannot be used outside of an IDBTransactionEvent context), then I could see this making sense. Otherwise could you please explain why this is? This does seem to be loosely what's intended...more below... Speccing such transactions: After thinking about this, I only see a couple options
Re: [IndexedDB] Implicit transactions
On 8/4/2010 10:24 AM, Jeremy Orlow wrote: Jonas/Shawn: Since it seems you've been getting some feedback on your implementation, do you have any data to suggest that implicit transactions are being used and considered helpful in the wild? I have not yet seen any specific feedback about it as of yet. Cheers, Shawn smime.p7s Description: S/MIME Cryptographic Signature
Re: [IndexedDB] Implicit transactions
On 8/4/2010 8:42 AM, Jeremy Orlow wrote: In the IndexedDB spec, there are two ways to create a transaction. One is explicit (by calling IDBDatabase.transaction()) and one is implicit (for example, by calling IDBDatabase.objectStore.get(someKey)). I have questions about the latter, but before bringing these up, I think it might be best to give a bit of background (as I understand it) to make sure we're all on the same page: If I recall correctly, the original proposal from us basically said that IDBDatabase.objectStore(foo, [mode]) was just a shortcut for IDBDatabase.transaction(foo, [mode]).getObjectStore(foo); I'm not sure if putting some text like that would help make things clearer though. Cheers, Shawn smime.p7s Description: S/MIME Cryptographic Signature
Re: [IndexedDB] Implicit transactions
On Wed, Aug 4, 2010 at 6:33 PM, Shawn Wilsher sdwi...@mozilla.com wrote: On 8/4/2010 8:42 AM, Jeremy Orlow wrote: In the IndexedDB spec, there are two ways to create a transaction. One is explicit (by calling IDBDatabase.transaction()) and one is implicit (for example, by calling IDBDatabase.objectStore.get(someKey)). I have questions about the latter, but before bringing these up, I think it might be best to give a bit of background (as I understand it) to make sure we're all on the same page: If I recall correctly, the original proposal from us basically said that IDBDatabase.objectStore(foo, [mode]) was just a shortcut for IDBDatabase.transaction(foo, [mode]).getObjectStore(foo); I'm not sure if putting some text like that would help make things clearer though. Whoatransaction() is synchronous?!? Ok, so I guess the entire premise of my question was super confused. :-) But I'm not sure I like that at all since it means that I will have to open at least one object store every time I do any transaction. I.e. I can't save my favorite object stores and indexes to variables and then use them freely within transactions, which is something I expect most users will want want to do. Having a cute shortcut to cut down on one async call per transaction might be a good idea. But forcing me to call .objectStore() (and possibly .index() or others) for the first operation of every transaction seems sub-optimal. I can double check with some real web developers around Google, but I'm pretty sure they'll much rather make an asynchronous call to start a transaction to get back execution within an IDBTransactionEvent context rather than having to do repeated objectStore() and .index() calls to start every single transaction. And the more I think about this, the more I'm skeptical that any sort of synchronous transaction starting code is worth the complicated semantics. I mean, in reality, it saves very little code. And although it makes sample code a bit prettier to look at (I believe this was one of the original selling points), I think it's going to confuse developers more than it'll help them--in the long run. J
Re: [IndexedDB] Implicit transactions
On 8/4/2010 10:53 AM, Jeremy Orlow wrote: Whoatransaction() is synchronous?!? Ok, so I guess the entire premise of my question was super confused. :-) It is certainly spec'd that way [1]. The locks do not get acquired until the first actual bit of work is done though. Cheers, Shawn [1] http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#database-interface smime.p7s Description: S/MIME Cryptographic Signature
Re: [IndexedDB] Implicit transactions
For what it's worth I haven't found using it this way to be that hard or confusing but that could be because I'm a little more aware of the underlying implications when opening object stores. -Mikeal On Wed, Aug 4, 2010 at 11:47 AM, Shawn Wilsher sdwi...@mozilla.com wrote: On 8/4/2010 10:53 AM, Jeremy Orlow wrote: Whoatransaction() is synchronous?!? Ok, so I guess the entire premise of my question was super confused. :-) It is certainly spec'd that way [1]. The locks do not get acquired until the first actual bit of work is done though. Cheers, Shawn [1] http://dvcs.w3.org/hg/IndexedDB/raw-file/tip/Overview.html#database-interface