Skip to content

Fix for high concurrency issue #4

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

Merged
merged 4 commits into from
Apr 25, 2023
Merged

Conversation

billwashere
Copy link
Contributor

@billwashere billwashere commented Mar 10, 2018

This pull request does two changes

  1. Changes the datatype on the ops and snapshots tables to JSONB

  2. Attempts to resolve the high concurrency issue but committing the snapshot and operation in one transaction

Copy link
Member

@nornagon nornagon left a comment

Choose a reason for hiding this comment

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

Thanks for this PR! The jsonb and connection pooling stuff looks great, but I'm not ready to merge the change to the commit query. If you want to split those other two changes out into a separate PR, I'll merge those, but if you'd rather work on the query too and merge it all together then that's fine too.

README.md Outdated
## Usage

`sharedb-postgres` wraps native [node-postgres](https://github.com/brianc/node-postgres), and it supports the same configuration options.
`sharedb-postgres-jsonb` wraps native [node-postgres](https://github.com/brianc/node-postgres), and it supports the same configuration options.
Copy link
Member

Choose a reason for hiding this comment

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

can change this back :)

index.js Outdated
@@ -10,6 +10,7 @@ function PostgresDB(options) {
this.closed = false;

this.pg_config = options;
this.pool = new pg.Pool(this.pg_config)
Copy link
Member

Choose a reason for hiding this comment

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

Looks like the indentation is off here, please use 2-space indentation :)

structure.sql Outdated
@@ -14,3 +14,13 @@ CREATE TABLE snapshots (
data json not null,
PRIMARY KEY (collection, doc_id)
);

ALTER TABLE ops
Copy link
Member

Choose a reason for hiding this comment

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

Just fold the data type back into the CREATE TABLE statements

index.js Outdated
callback(err);
return;
}
/*const*/ var query = {
Copy link
Member

Choose a reason for hiding this comment

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

I think it's fine to use const directly here, especially since you're using string interpolation 2 lines below--this is ES6

index.js Outdated
Select n.* From ( select $1 c, $2 t, $3::integer v, $6::jsonb daa)
n
where (v = (select max(version)+1 v from ops where collection = $1 and doc_id = $2) or not exists (select 1 from ops where collection = $1 and doc_id = $2 for update)) and exists (select 1 from snaps)
Returning version`,
Copy link
Member

Choose a reason for hiding this comment

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

I found this query really hard to follow, even after reformatting and reindenting it. It's doing a lot of stuff, but I don't know if it's correct--could you explain (perhaps in a comment in the file) what this is doing and why?

Here's the reformatted version I made:

WITH snaps AS (
  INSERT INTO snapshots (collection, doc_id, doc_type, version, data)
  SELECT n.*
  FROM (SELECT $1 c, $2 d, $4 t, $3::integer v, $5::jsonb daa) n 
  WHERE v = (
    SELECT version+1 v
    FROM snapshots
    WHERE collection = $1 AND doc_id = $2
    FOR UPDATE
  ) OR NOT EXISTS (
    SELECT 1
    FROM snapshots
    WHERE collection = $1 AND doc_id = $2
    FOR UPDATE
  )
  ON CONFLICT (collection, doc_id) DO UPDATE SET version = $3, data = $5, doc_type = $4
  RETURNING version
)
INSERT INTO ops (collection, doc_id, version, operation)
SELECT n.* FROM (SELECT $1 c, $2 t, $3::integer v, $6::jsonb daa) n 
WHERE (
  v = (
    SELECT max(version)+1 v
    FROM ops
    WHERE collection = $1 AND doc_id = $2
  ) OR NOT EXISTS (
    SELECT 1
    FROM ops
    WHERE collection = $1 AND doc_id = $2
    FOR UPDATE
  )
) AND EXISTS (SELECT 1 FROM snaps)
RETURNING version

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yeah it non-trivial sql. I've now added the following comment

This query uses common table expression to upsert the snapshot table
(iff the new version is exactly 1 more than the latest table or if
the document id does not exists)

It will then Insert into the ops table if it is exactly 1 more than the
latest table or it the first operation and iff the previous insert into
the snapshot table is successful.

This result of this query the version of the newly inserted operation

If either the ops or the snapshot insert fails then 0 rows are returned

If 0 zeros are return then the callback must return false

index.js Outdated
})
client.query(query, (err, res) => {
if (err) {
console.log(err.stack)
Copy link
Member

Choose a reason for hiding this comment

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

don't log anything from this library—that's up to the client.

@billwashere
Copy link
Contributor Author

Hi @nornagon
I've split out pooling into a seperate change - #5

@billwashere
Copy link
Contributor Author

I've this pull request with the required changes.

Additionally

  1. Commit no longer requires jsonb, it works fine without it
  2. On close, the connection pool drains

@jasoniangreen
Copy link

Hey @billwashere and @nornagon, what is the state of this? Do you need any help?

@billwashere
Copy link
Contributor Author

I believe that it working correctly, however due to the fact that it is such a big change more testing may be required (I'll leave how much testing to @nornagon).

If you want to try it out and see if you can break it, that would be great.

@nornagon
Copy link
Member

Would you be able to rebase this on top of master? It looks like mostly minor conflicts. Also retitle the PR, since this is now only addressing the concurrency issue.

Thanks! If this is reported working for a few people, I'm happy to merge it (at least, once I sit down and actually understand what's going on with the query...). The code as it is is not particularly well tested, so new untested code at least won't be a regression, but it'd be great to have better test coverage! especially cool would be if you could construct a test that fails with the old code but passes with the new.

@billwashere billwashere changed the title JSONB, PG library, and check max update Fix for high concurrency issue Jun 10, 2018
@ianberdin
Copy link

@billwashere can you merge this to master and update npm package?

@Utwo
Copy link

Utwo commented Mar 23, 2021

@billwashere can you merge this to master and update npm package?

I think you can use this package: https://github.com/plotdb/sharedb-postgres

@nornagon
Copy link
Member

if @zbryikt or someone wants to take over maintenance of this repo, I'm happy to grant access.

@alecgibson alecgibson merged commit 19210ee into share:main Apr 25, 2023
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.

6 participants