- From: Israel Hilerio <israelh@microsoft.com>
- Date: Mon, 5 Mar 2012 20:09:51 +0000
- To: "Jonas Sicking (jonas@sicking.cc)" <jonas@sicking.cc>
- CC: "jsbell@chromium.org" <jsbell@chromium.org>, "public-webapps@w3.org" <public-webapps@w3.org>
The approach you described makes sense to us. Thanks for clarifying. Israel On Saturday, March 03, 2012 5:07 PM, Jonas Sicking wrote: > On Fri, Mar 2, 2012 at 8:49 PM, Israel Hilerio <israelh@microsoft.com> wrote: > > We would like some clarification on this scenario. When you say that > > FF will result on 1 index entry for each index that implies that the > > duplicates are automatically removed. That implies that the > > multiEntry flag doesn't take unique into consideration. Is this correct? > > Not quite. > > In Firefox multiEntry indexes still honor the 'unique' constraint. > However whenever a multiEntry index adds an Array of entries to an index, it > first removes any duplicate values from the Array. Only after that do we start > inserting entries into the index. But if such an insertion does cause a 'unique' > constraint violation then we still abort with a ConstraintError. > > Let me show some examples: > > store = db.createObjectStore("store"); > index = store.createIndex("index", "a", { multiEntry: true } ); store.add({ x: 10 }, > 1); // Operation succeeds, store contains one entry store.add({ a: 10 }, 2); // > Operation succeeds, store contains two entries // index contains one entry: 10 > -> 2 store.add({ a: [10, 20, 20] }, 3); // Operation succeeds, store contains three > entries // index contains three entries: 10->2, 10->3, 20->3 store.add({ a: [30, > 30, 30] }, 4); // Operation succeeds, store contains four entries // index > contains four entries: 10->2, 10->3, 20->3, 30->4 store.put({ a: [20, 20] }, 3); // > Operation succeeds, store contains four entries // index contains three entries: > 10->2, 20->3, 30->4 > > > Similar things happen for unique entries (assume that the transaction has a > errorhandler which calls preventDefault() on all error events so that the > transaction doesn't get aborted by the failed inserts) > > store = db.createObjectStore("store"); > index = store.createIndex("index", "a", { multiEntry: true, unique: true } ); > store.add({ x: 10 }, 1); // Operation succeeds, store contains one entry > store.add({ a: 10 }, 2); // Operation succeeds, store contains two entries // > index contains one entry: 10 -> 2 store.add({ a: [10] }, 3); // Operation fails due > to the 10 key already existing in the index store.add({ a: [20, 20, 30] }, 4); // > Operation succeeds, store contains three entries // index contains three > entries: 10->2, 20->4, 30->4 store.add({ a: [20, 40, 40] }, 5); // Operation fails > due to the 20 key already existing in the index store.add({ a: [40, 40] }, 6); // > Operation succeeds, store contains four entries // index contains four entries: > 10->2, 20->4, 30->4, 40->6 store.put({ a: [10] }, 4); // Operation fails due to the > 10 key already existing in the index // store still contains four entries // index > still contains four entries: 10->2, 20->4, 30->4, 40->6 store.put({ a: [10, 50] }, 2); > // Operation succeeds, store contains five entries // index contains six entries: > 10->2, 20->4, 30->4, 40->6, 50->2 > > > To put it in spec terms: > One way to fix this would be to add the following to "Object Store Storage > Operation" step 7.4: > "Also remove any duplicate elements from /index key/ such that only one > instance of the duplicate value exists in /index key/". > > Maybe also add a note which says: > "For example, the following value of /index key/ [10, 20, null, 30, 20] is > converted to [10, 20, 30]" > > > For what it's worth, we haven't implemented this in Firefox by preprocessing > the array to remove duplicate entries. Instead we for non-unique indexes keep > a btree key'ed on indexKey + primaryKey. When inserting into this btree we > simply ignore any collisions since they must be due to multiple identical entries > in a multiEntry array. > > For unique indexies we keep a btree key'ed on indexKey. If we hit a collision > when doing an insertion, and we're inserting into a multiEntry index, we do a > lookup to see what primaryKey the indexKey maps to. If it maps to the > primaryKey we're currently inserting for, we know that it was due to a > duplicate entry in the array and we just move on with no error. If it maps to > another primaryKey we roll back the operation and fire a ConstraintError. > > Let me know if there's still any scenarios that are unclear. > > / Jonas
Received on Monday, 5 March 2012 20:10:38 UTC