Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Flush write buffer when full #253

Closed
wants to merge 6 commits into from
Closed

Conversation

mheinzel
Copy link
Collaborator

No description provided.

modifyMVar_ (tableContent thEnv) $ \tableContent -> do
let !wb = WB.addEntries (resolveMupsert (tableConfig th)) es $
tableWriteBuffer tableContent
if WB.sizeInBytes wb <= fromIntegral (confWriteBufferAlloc (tableConfig th))
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might actually just want to look at number of entries for now.

For the runs, this simplifies things quite a bit (e.g. with mupsert a merged run might end up larger than the sum of its inputs), so it would make sense to do it for the write buffer as well.

Copy link
Collaborator

@jorisdral jorisdral Jun 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be useful to still keep the size calculation in here

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think on balance we should drop it (but keep the code on a branch in case we decide to resurrect it).

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I think we can keep this branch. I've opened #259 with the alternative approach based on number of entries

Copy link
Collaborator

@jorisdral jorisdral left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good already! I'll take over this PR and make changes if necessary

test/Test/Database/LSMTree/Internal/Merge.hs Outdated Show resolved Hide resolved
src/Database/LSMTree/Internal/WriteBuffer.hs Outdated Show resolved Hide resolved
src/Database/LSMTree/Internal/WriteBuffer.hs Outdated Show resolved Hide resolved
src/Database/LSMTree/Internal/WriteBuffer.hs Show resolved Hide resolved
src/Database/LSMTree/Internal/WriteBuffer.hs Outdated Show resolved Hide resolved
test/Test/Database/LSMTree/Internal/Lookup.hs Outdated Show resolved Hide resolved
src/Database/LSMTree/Internal.hs Show resolved Hide resolved
Comment on lines +561 to +573
flushWriteBuffer ::
m ~ IO
=> TableHandleEnv m h
-> Levels (Handle h)
-> WriteBuffer
-> m (TableContent h)
flushWriteBuffer thEnv levels wb = do
n <- incrUniqCounter (tablesSessionUniqCounter thEnv)
let runPaths = Paths.runPath (tableSessionRoot thEnv) n
run <- Run.fromWriteBuffer (tableHasFS thEnv) runPaths wb
let levels' = addRunToLevels run levels
return TableContent {
tableWriteBuffer = WB.empty
, tableLevels = levels'
, tableCache = mkLevelsCache levels'
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should only partially flush the write buffer: a batch of updates might have overfilled the write buffer by a lot

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't matter if we go by key count only.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh I see. Perhaps it'd be simpler to split a batch of inserts so that we never over-fill the write buffer.

Or even simpler, if the batch would take us over the keys limit, flush the buffer as-is (so it's not 100% full) and put the new batch into the new (empty) buffer. That works except when the buffer is hardly full but the batch is so large it'd take us over the limit. In that case we'd need to split batches of inserts.

modifyMVar_ (tableContent thEnv) $ \tableContent -> do
let !wb = WB.addEntries (resolveMupsert (tableConfig th)) es $
tableWriteBuffer tableContent
if WB.sizeInBytes wb <= fromIntegral (confWriteBufferAlloc (tableConfig th))
Copy link
Collaborator

@jorisdral jorisdral Jun 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wonder if it would be useful to still keep the size calculation in here

@jorisdral jorisdral self-assigned this Jun 17, 2024
@jorisdral jorisdral force-pushed the mheinzel/table-write-flush branch 2 times, most recently from 3429b6a to 2b588e8 Compare June 18, 2024 12:44
mheinzel and others added 5 commits June 18, 2024 14:57
The directory that runs were created in was deleted accidentally, causing an
`FsError` to appear after the first benchmark.
Copy link
Collaborator

@dcoutts dcoutts left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is looking ok, but I agree that the way to go for now is just size in number of keys, and not size in a bytes measure.

writeBufferContent :: !(Map SerialisedKey (Entry SerialisedValue SerialisedBlob))
-- | Keeps track of the total size of keys and values in the buffer.
-- This means reconstructing the 'WB' constructor on every update.
, writeBufferSizeBytes :: {-# UNPACK #-} !Int
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Following our discussion yesterday, is it worth tracking this? We concluded that the size measure we would use for the LSM merging would be the number of keys rather than size of keys + values. There's a non-trivial cost to tracking it here in the WriteBuffer. Is it worth paying?

Provided we keep the branch, we can always grab the code again if we decide we do need it.

let (!wb', !s') = runState (insert k wb) s
in WB wb' s'
where
-- TODO: this seems inelegant, but we want to avoid traversing the Map twice
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And this is only needed to track the size measure.

modifyMVar_ (tableContent thEnv) $ \tableContent -> do
let !wb = WB.addEntries (resolveMupsert (tableConfig th)) es $
tableWriteBuffer tableContent
if WB.sizeInBytes wb <= fromIntegral (confWriteBufferAlloc (tableConfig th))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think on balance we should drop it (but keep the code on a branch in case we decide to resurrect it).

Comment on lines +561 to +573
flushWriteBuffer ::
m ~ IO
=> TableHandleEnv m h
-> Levels (Handle h)
-> WriteBuffer
-> m (TableContent h)
flushWriteBuffer thEnv levels wb = do
n <- incrUniqCounter (tablesSessionUniqCounter thEnv)
let runPaths = Paths.runPath (tableSessionRoot thEnv) n
run <- Run.fromWriteBuffer (tableHasFS thEnv) runPaths wb
let levels' = addRunToLevels run levels
return TableContent {
tableWriteBuffer = WB.empty
, tableLevels = levels'
, tableCache = mkLevelsCache levels'
}
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wouldn't matter if we go by key count only.

@jorisdral
Copy link
Collaborator

jorisdral commented Jun 20, 2024

We are going to use a write buffer allocation method that is defined in terms of number of entries, instead of number of bytes. We're keeping the code in this PR around in case we want to change the write buffer allocation method to byte size later, and we've opened #259 for the alternative method.

@jorisdral jorisdral closed this Jun 20, 2024
@jorisdral jorisdral deleted the mheinzel/table-write-flush branch July 2, 2024 10:44
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants