Re: Property index replacement / evolution
Hi Ian, On Mon, Aug 8, 2016 at 3:41 PM, Ian Bostonwrote: > > If every successful commit writes the root node, due to every update > updating a sync prop index, this leaves me wondering how the delayed sync > reduces the writes to the root node ? > > I thought the justification of the 1s sync operation was to reduce the > writes to the root node to n/s where n is the number of instances in the > cluster, however based on what you are telling me the rate is (m+n)/s where > m is the total commits per second of the whole cluster. I understand that > the update to test for a conflicted commit may not be the same as the > update of _lastRevs, but in MongoDB both update the MongoDB document. > I'm not sure of the exact numbers around how MongoDB would perform for lots of edits to the same document. There's a bit of difference between _lastRev write and commit-root conditional update - commit-root update is a change on a sub-document... so, something like 'set "_revision.rX"="c" on _id=0:/ iff "_conflict.rX"' doesn't exist. While last rev updates change the same key across commits from the same cluster node - something like 'set "_lastRevs.r0-0-X"="rY-0-X" '. I think the idea is to avoid any conflict on MongoDB's update statements. I'm not sure if such edits (edits to same doc but at a different sub-doc/key) degrade performance badly. Thanks, Vikas PS: I wonder if we should open a different thread as it seems to be digressing from the subject :)
Re: Property index replacement / evolution
Hi Vikas, On 8 August 2016 at 14:13, Vikas Saurabhwrote: > Hi Ian, > > On Sun, Aug 7, 2016 at 10:01 AM, Ian Boston wrote: > > Also, IIRC, the root document is not persisted on every commit, but > > synchronized periodically (once every second) similar to fsync on a disk. > > So the indexes (in fact all Oak Documents) are synchronous on the local > Oak > > instance and are synchronous on remote Oak instances but with a minimum > > data latency of the root document sync rate (1s). IIUC the 1 second sync > > period is a performance optimisation as the root document must be updated > > by every commit and hence is a global singleton in an Oak cluster, and > > already hot as you point out in 3. > > > > Just to clarify a bit. There are potentially 2 updates that can modify > root document. > With every commit, oak (document mk) defines a document to be > commit-root. That's root of the sub-tree which changes. A commit is > successful if commit-root could be conditionally updated (condition to > see if the commit conflicted with something else or not). With > synchronous prop indices, commit root usually is at root - so each > successful commit would write to root. That's what Michael was > pointing to in point3. > The other update is about asynchronous update of _lastRevs - _lastRevs > control visibility horizon. For local nodes, a pending list of updates > is kept in memory so local sessions/builders get to see committed > changes. These are pushed to persistence mongo during background > update which defaults at 1 s interval. So, other cluster nodes don't > see changes immediately. > Thanks for the explanation. I learnt something more. If every successful commit writes the root node, due to every update updating a sync prop index, this leaves me wondering how the delayed sync reduces the writes to the root node ? I thought the justification of the 1s sync operation was to reduce the writes to the root node to n/s where n is the number of instances in the cluster, however based on what you are telling me the rate is (m+n)/s where m is the total commits per second of the whole cluster. I understand that the update to test for a conflicted commit may not be the same as the update of _lastRevs, but in MongoDB both update the MongoDB document. Best Regards Ian > > Thanks, > Vikas >
Re: Property index replacement / evolution
Hi Ian, On Sun, Aug 7, 2016 at 10:01 AM, Ian Bostonwrote: > Also, IIRC, the root document is not persisted on every commit, but > synchronized periodically (once every second) similar to fsync on a disk. > So the indexes (in fact all Oak Documents) are synchronous on the local Oak > instance and are synchronous on remote Oak instances but with a minimum > data latency of the root document sync rate (1s). IIUC the 1 second sync > period is a performance optimisation as the root document must be updated > by every commit and hence is a global singleton in an Oak cluster, and > already hot as you point out in 3. > Just to clarify a bit. There are potentially 2 updates that can modify root document. With every commit, oak (document mk) defines a document to be commit-root. That's root of the sub-tree which changes. A commit is successful if commit-root could be conditionally updated (condition to see if the commit conflicted with something else or not). With synchronous prop indices, commit root usually is at root - so each successful commit would write to root. That's what Michael was pointing to in point3. The other update is about asynchronous update of _lastRevs - _lastRevs control visibility horizon. For local nodes, a pending list of updates is kept in memory so local sessions/builders get to see committed changes. These are pushed to persistence mongo during background update which defaults at 1 s interval. So, other cluster nodes don't see changes immediately. Thanks, Vikas
Re: Are NodeStore.createBlob and NodeStore.getBlob not symmetric for the SegmentNodeStore?
On 8.8.16 12:46 , Robert Munteanu wrote: On Mon, 2016-08-08 at 12:45 +0200, Michael Dürig wrote: The segment node store inlines blobs up to a size of 16512 bytes. This is probably the reason you are not able to get them from the blob store. Good point. So it's expected that this happens and to test blob handling I would need to use 'large' blobs? If you want them to go into the blob store, yes. Michael Robert Michael On 8.8.16 12:38 , Robert Munteanu wrote: Hi, I'm trying to understand the behaviour of NodeStore.createBlob and NodeStore.getBlob. For context, I'm experimenting with creating a MultiplexingNodeStore [1] , and this multiplexing would neet to include the blob handling as well. But before that, I'm trying to understand something basic :-) I have created a SegmentNodeStore with a FileBlobStore BlobStore blobStore = new FileBlobStore(blobStorePath); FileStore store = FileStore.builder(storePath).withBlobStore(blobStore).build(); SegmentNodeStore instance = SegmentNodeStore.builder(store).build(); After that I have tried to retrieve a blob from the same store Blob createdBlob = globalStore.createBlob(SMALL_BLOB); Blob retrievedBlob = globalStore.getBlob(createdBlob.getReference()); where private static final InputStream SMALL_BLOB = new ByteArrayInputStream("hello, world".getBytes()); To my surprise, retrievedBlob is null, since it has a null id. I've traced the calls to understand what is going on, and in SegmentBlob.getBlobId() the blobId is null, since the 'head' variable is the following code has the value 0. byte head = segment.readByte(offset); if ((head & 0xf0) == 0xe0) { // 1110 : external value, small blob ID return readShortBlobId(segment, offset, head); } else if ((head & 0xf8) == 0xf0) { // 0xxx: external value, long blob ID return readLongBlobId(segment, offset); } else { return null; } Now, this works as expected for a DocumentNodeStore backed by H2, so something is not entirely right. So my question is - why does this happen? 1) Is this sequence of calls (createBlob/getBlob) not supposed to be symmetric? 2) Am I configuring the SegmentNodeStore incorrectly? 3) Is it a bug to file against the SegmentNodeStore? If you're curious, the full test code is at [2], although I haven't committed the variant which checks the SegmentNodeStore for blob handling consistency. Thanks, Robert [1]: https://github.com/apache/jackrabbit-oak/compare/trunk...rombe rt:f eatures/nodestore-multiplex?expand=1 [2]: https://github.com/rombert/jackrabbit-oak/blob/99cd3d8b81213fa 03a2 ebee2ad754081dbd5977f/oak- it/src/test/java/org/apache/jackrabbit/oak/plugins/memory/multiplex /Mul tiplexingMemoryNodeStoreTest.java
Re: Are NodeStore.createBlob and NodeStore.getBlob not symmetric for the SegmentNodeStore?
On Mon, 2016-08-08 at 12:45 +0200, Michael Dürig wrote: > The segment node store inlines blobs up to a size of 16512 bytes. > This > is probably the reason you are not able to get them from the blob > store. Good point. So it's expected that this happens and to test blob handling I would need to use 'large' blobs? Robert > > Michael > > On 8.8.16 12:38 , Robert Munteanu wrote: > > > > Hi, > > > > I'm trying to understand the behaviour of NodeStore.createBlob and > > NodeStore.getBlob. For context, I'm experimenting with creating a > > MultiplexingNodeStore [1] , and this multiplexing would neet to > > include > > the blob handling as well. > > > > But before that, I'm trying to understand something basic :-) > > > > I have created a SegmentNodeStore with a FileBlobStore > > > > BlobStore blobStore = new FileBlobStore(blobStorePath); > > FileStore store = > > FileStore.builder(storePath).withBlobStore(blobStore).build(); > > SegmentNodeStore instance = > > SegmentNodeStore.builder(store).build(); > > > > After that I have tried to retrieve a blob from the same store > > > > Blob createdBlob = globalStore.createBlob(SMALL_BLOB); > > Blob retrievedBlob = > > globalStore.getBlob(createdBlob.getReference()); > > > > where > > > > private static final InputStream SMALL_BLOB = new > > ByteArrayInputStream("hello, world".getBytes()); > > > > To my surprise, retrievedBlob is null, since it has a null id. > > > > I've traced the calls to understand what is going on, and in > > SegmentBlob.getBlobId() the blobId is null, since the 'head' > > variable > > is the following code has the value 0. > > > > byte head = segment.readByte(offset); > > if ((head & 0xf0) == 0xe0) { > > // 1110 : external value, small blob ID > > return readShortBlobId(segment, offset, head); > > } else if ((head & 0xf8) == 0xf0) { > > // 0xxx: external value, long blob ID > > return readLongBlobId(segment, offset); > > } else { > > return null; > > } > > > > Now, this works as expected for a DocumentNodeStore backed by H2, > > so > > something is not entirely right. > > > > So my question is - why does this happen? > > > > 1) Is this sequence of calls (createBlob/getBlob) not supposed to > > be > > symmetric? > > 2) Am I configuring the SegmentNodeStore incorrectly? > > 3) Is it a bug to file against the SegmentNodeStore? > > > > If you're curious, the full test code is at [2], although I haven't > > committed the variant which checks the SegmentNodeStore for blob > > handling consistency. > > > > Thanks, > > > > Robert > > > > [1]: https://github.com/apache/jackrabbit-oak/compare/trunk...rombe > > rt:f > > eatures/nodestore-multiplex?expand=1 > > [2]: https://github.com/rombert/jackrabbit-oak/blob/99cd3d8b81213fa > > 03a2 > > ebee2ad754081dbd5977f/oak- > > it/src/test/java/org/apache/jackrabbit/oak/plugins/memory/multiplex > > /Mul > > tiplexingMemoryNodeStoreTest.java > >
Re: Are NodeStore.createBlob and NodeStore.getBlob not symmetric for the SegmentNodeStore?
The segment node store inlines blobs up to a size of 16512 bytes. This is probably the reason you are not able to get them from the blob store. Michael On 8.8.16 12:38 , Robert Munteanu wrote: Hi, I'm trying to understand the behaviour of NodeStore.createBlob and NodeStore.getBlob. For context, I'm experimenting with creating a MultiplexingNodeStore [1] , and this multiplexing would neet to include the blob handling as well. But before that, I'm trying to understand something basic :-) I have created a SegmentNodeStore with a FileBlobStore BlobStore blobStore = new FileBlobStore(blobStorePath); FileStore store = FileStore.builder(storePath).withBlobStore(blobStore).build(); SegmentNodeStore instance = SegmentNodeStore.builder(store).build(); After that I have tried to retrieve a blob from the same store Blob createdBlob = globalStore.createBlob(SMALL_BLOB); Blob retrievedBlob = globalStore.getBlob(createdBlob.getReference()); where private static final InputStream SMALL_BLOB = new ByteArrayInputStream("hello, world".getBytes()); To my surprise, retrievedBlob is null, since it has a null id. I've traced the calls to understand what is going on, and in SegmentBlob.getBlobId() the blobId is null, since the 'head' variable is the following code has the value 0. byte head = segment.readByte(offset); if ((head & 0xf0) == 0xe0) { // 1110 : external value, small blob ID return readShortBlobId(segment, offset, head); } else if ((head & 0xf8) == 0xf0) { // 0xxx: external value, long blob ID return readLongBlobId(segment, offset); } else { return null; } Now, this works as expected for a DocumentNodeStore backed by H2, so something is not entirely right. So my question is - why does this happen? 1) Is this sequence of calls (createBlob/getBlob) not supposed to be symmetric? 2) Am I configuring the SegmentNodeStore incorrectly? 3) Is it a bug to file against the SegmentNodeStore? If you're curious, the full test code is at [2], although I haven't committed the variant which checks the SegmentNodeStore for blob handling consistency. Thanks, Robert [1]: https://github.com/apache/jackrabbit-oak/compare/trunk...rombert:f eatures/nodestore-multiplex?expand=1 [2]: https://github.com/rombert/jackrabbit-oak/blob/99cd3d8b81213fa03a2 ebee2ad754081dbd5977f/oak- it/src/test/java/org/apache/jackrabbit/oak/plugins/memory/multiplex/Mul tiplexingMemoryNodeStoreTest.java