Giter Club home page Giter Club logo

Comments (2)

readevalprint avatar readevalprint commented on June 23, 2024

Yeah this just hit me with postgres too.
This email explains what it means: http://www.postgresql.org/message-id/[email protected]

a lock on a select result means that
you've guaranteed that no one else can change the rows you selected.
In an outer join it's impossible to guarantee that --- someone could
insert a B row that matches a formerly unmatched A row. If you now
re-did the SELECT you would get a different result, ie, your
null-extended A row would be replaced by a normal row, even though you
had lock on that A row. (This does not speak to the question of new
rows showing up in the second SELECT --- that's always possible. The
point is that a row you got the first time is now different despite
being "locked".)

from django-bitcoin.

devinjames avatar devinjames commented on June 23, 2024

The issue is that wallet__isnull=True is attempting to lock the null wallet rows and the other statements are trying to lock the addresses table, the thing is postgres can't guarantee that for the transaction the wallet result will stay constant, as far as postgres knows some other transaction could run in parallel and change an entry in the wallet table making it's old statement invalid

It's not a perfect solution but if you need a workaround for now you can add a distributed lock on the new_bitcoin_address to ensure that the function doesn't run in parallel any two times in the system:

@distributedlock('get_new_address') def new_bitcoin_address():

Update this line in the 'new_bitcoin_address' function:
updated = BitcoinAddress.objects.select_for_update().filter(id=bp.id, active=False, least_received__lte=0, wallet__isnull=True).update(active=True)
with
updated = BitcoinAddress.objects.select_for_update().filter(id=bp.id).update(active=True)

The criteria are already set by bp.id, so long as nothing has utilized that address within the same timeframe of this occurrence of the function there will be no issues with duplicity in the database. That is the reason for the distributed lock, ensuring that the function cannot run in parallel within your app.

For the same reason you also have to modify the call in the Wallet.receiving_address method.

This
updated = BitcoinAddress.objects.select_for_update().filter(id=addr.id, active=True, least_received__lte=0, wallet__isnull=True).update(active=True, wallet=self)
becomes
updated = BitcoinAddress.objects.select_for_update().filter(id=addr.id, active=True).update(wallet=self)

The addr variable at this point should direct towards an address id, there is no reason to run the rest of the criteria since it's been executed already, arguably active=True isn't necessary at this point, as it should have been set in the new_bitcoin_address call. There is also no reason for the active=True portion in the update() call at the end of the function since it was already set in the new_bitcoin_address

I hope that helps, there has to be a better way but unfortunately with the way it is built right now it'll take some design overhauls or a manual select statement that doesn't use an outer join, unfortunately I am not an SQL genius :(.

from django-bitcoin.

Related Issues (18)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.