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

Resolving TODO: PrimVar for UniqCounter #508

Merged
merged 2 commits into from
Jan 8, 2025

Conversation

recursion-ninja
Copy link
Collaborator

Description

Updating the mutable pointer type of UniqCounter to be a PrimVar rather than a StrictMVar.

src/Database/LSMTree/Internal/UniqCounter.hs Outdated Show resolved Hide resolved
--
-- TODO: could we use a PrimVar here?
newtype UniqCounter m = UniqCounter (StrictMVar m Word64)
newtype UniqCounter m = UniqCounter (PrimVar (PrimState m) Word64)
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
newtype UniqCounter m = UniqCounter (PrimVar (PrimState m) Word64)
newtype UniqCounter s = UniqCounter (PrimVar s Word64)

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Changing (PrimState m) to s here causes a lot of "upstream" breakages in the type-class constraint which call functions that interact with UniqCounter. Generally it requires creating a new type variable s in addition to the existing m, and adding PrimState m ~ s in a lot of places.

Is there a technical reason to make this change? Performance or memory implications I might not be aware of?

Copy link
Collaborator

Choose a reason for hiding this comment

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

It's not incorrect, it's just more restrictive to require m instead of s. We should add at least a TODO to change it, even if it would cause code changes elsewhere


-- |
-- This call to @unsafeCoerce@ relies on the machine's binary representation of
-- the @Int@ type to be safe. The binary representation must be 64-bots wide, a
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
-- the @Int@ type to be safe. The binary representation must be 64-bots wide, a
-- the @Int@ type to be safe. The binary representation must be 64-bits wide, a

--
-- TODO: could we use a PrimVar here?
newtype UniqCounter m = UniqCounter (StrictMVar m Word64)
newtype UniqCounter m = UniqCounter (PrimVar (PrimState m) Word64)
Copy link
Collaborator

Choose a reason for hiding this comment

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

It's not incorrect, it's just more restrictive to require m instead of s. We should add at least a TODO to change it, even if it would cause code changes elsewhere

newtype UniqCounter m = UniqCounter (StrictMVar m Word64)
-- Additionally, it is safe to @unsafeCoerce@ between `Int` and `Word64` for
-- the same reason, the use must guarantee a 2's compliment representation for
-- signed integral types. See thethis module's @convert@ function for more info.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
-- signed integral types. See thethis module's @convert@ function for more info.
-- signed integral types. See this module's @convert@ function for more info.

Comment on lines 41 to 42
-- |
-- This call to @unsafeCoerce@ relies on the machine's binary representation of
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
-- |
-- This call to @unsafeCoerce@ relies on the machine's binary representation of
-- | This call to @unsafeCoerce@ relies on the machine's binary representation of

-- TODO: could we use a PrimVar here?
newtype UniqCounter m = UniqCounter (StrictMVar m Word64)
-- Additionally, it is safe to @unsafeCoerce@ between `Int` and `Word64` for
-- the same reason, the use must guarantee a 2's compliment representation for
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
-- the same reason, the use must guarantee a 2's compliment representation for
-- the same reason, the use must guarantee a 2's complement representation for

-- the @Int@ type to be safe. The binary representation must be 64-bots wide, a
-- given guarantee by the user according to the @README.md@. Additionally, the
-- binary representation of @Int@ must form an additive ring which is homomorphic
-- with @Word64@ (such as 2's compliment); i.e.:
Copy link
Collaborator

Choose a reason for hiding this comment

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

Suggested change
-- with @Word64@ (such as 2's compliment); i.e.:
-- with @Word64@ (such as 2's complement); i.e.:

Comment on lines 48 to 52
-- @
-- let limit = maxBound :: Int
-- in forall (x :: Int).
-- (unsafeCoerce limit :: Word64) + (unsafeCoerce x :: Word64) === unsafeCoerce (limit + x)
-- @
Copy link
Collaborator

Choose a reason for hiding this comment

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

Let's make this into a test!

-- TODO: could we use a PrimVar here?
newtype UniqCounter m = UniqCounter (StrictMVar m Word64)
-- Additionally, it is safe to @unsafeCoerce@ between `Int` and `Word64` for
-- the same reason, the use must guarantee a 2's compliment representation for
Copy link
Collaborator

Choose a reason for hiding this comment

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

Are there cases where ints are not represented as 2's complement? Does it depend on GHC, gcc, the OS, the machine architecture?

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.

I don't think there's any strong reason why the counter should be represented by a Word64 or an Int. So I don't think we need to get into the weeds about unsafe conversions. We can both UniqueCounter and Unique as Int and convert to RunNumber safely.

Similarly, I'm not sure there's any strong reason that RunNumber needs to be Word64 rather than Int.

-- @
{-# INLINE convert #-}
convert :: Int -> Word64
convert = unsafeCoerce
Copy link
Collaborator

Choose a reason for hiding this comment

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

I don't see why we need to unsafely coerce. An ordinary conversion should be just fine, no?

@dcoutts
Copy link
Collaborator

dcoutts commented Jan 7, 2025

I'll take this one over since @recursion-ninja is away. I'm going to simplify to use Int everywhere.

@jorisdral
Copy link
Collaborator

Similarly, I'm not sure there's any strong reason that RunNumber needs to be Word64 rather than Int.

We only use RunNumber as the name for runs, and I figured it would be nicest to have only positive integers as names

@dcoutts dcoutts force-pushed the recursion-ninja/UniqCounter-primitive branch from 6387479 to d406ff0 Compare January 7, 2025 14:30
@dcoutts
Copy link
Collaborator

dcoutts commented Jan 7, 2025

We only use RunNumber as the name for runs, and I figured it would be nicest to have only positive integers as names

We still can. We initialise the unique counter at 0, so they'll all be positive.

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.

LGTM

@jorisdral
Copy link
Collaborator

We only use RunNumber as the name for runs, and I figured it would be nicest to have only positive integers as names

We still can. We initialise the unique counter at 0, so they'll all be positive.

I was thinking about when the counter would wrap around from maxBound to minBound when we increment it. It's only going to happen after a verrrry long time so it's unlikely any cardano node would ever reach that point, but I also don't see it costing us much to use Word64. The run number / table ID / cursor ID are only used as names after all, not to compute anything with

@dcoutts dcoutts force-pushed the recursion-ninja/UniqCounter-primitive branch from d406ff0 to 6fa48f1 Compare January 7, 2025 14:57
@dcoutts
Copy link
Collaborator

dcoutts commented Jan 7, 2025

It's only going to happen after a verrrry long time so it's unlikely any cardano node would ever reach that point

It certainly would not happen for a Cardano node since those only run on 64bit platforms.

And for any other use case on a 32bit platform, it would only happen after 2 billion table duplications within the same session. At which point the bigger problem would be the clashes not the negative number.

recursion-ninja and others added 2 commits January 8, 2025 00:04
RunNumber is rather unnecessarily a Word64 when Int would do just fine
and involve fewer conversions.

Also add TableId and CursorId newtypes (rather than raw Word64) and make
these use Int too for the same reasons.

Add and use direct conversion functions uniqueTo{Table,Cursor}Id.
@dcoutts dcoutts force-pushed the recursion-ninja/UniqCounter-primitive branch from 6fa48f1 to 4dcde00 Compare January 8, 2025 00:06
@dcoutts dcoutts enabled auto-merge January 8, 2025 00:06
@dcoutts dcoutts added this pull request to the merge queue Jan 8, 2025
Merged via the queue into main with commit 39343e5 Jan 8, 2025
27 checks passed
@dcoutts dcoutts deleted the recursion-ninja/UniqCounter-primitive branch January 8, 2025 00:55
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