Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QSqlDatabase using SQlite and timing of concurrent write attempts

QSqlDatabase using SQlite and timing of concurrent write attempts

Scheduled Pinned Locked Moved Solved General and Desktop
11 Posts 4 Posters 1.7k Views 3 Watching
  • Oldest to Newest
  • Newest to Oldest
  • Most Votes
Reply
  • Reply as topic
Log in to reply
This topic has been deleted. Only users with topic management privileges can see it.
  • l3u_L Offline
    l3u_L Offline
    l3u_
    wrote on last edited by
    #1

    Hi :-)

    I'm writing a program using an SQLite database. It can either start a TCP server or client, so that all connected instances of it (that live on different computers) can broadcast changes and all databases are kept in sync (using the same central database all clients can connect to is not possible/wanted). At least, that's what it should be when I'm finished ;-)

    I already implemented broadcasting all changes that are done on the server instance to all clients. This is no problem and already works.

    But now, it's about how to implement a change coming from a client. I thought about not actually changing anything, but only to send a change request to the server. If everything is fine, the server applies the change and broadcasts it, as it would be done if the change originated from the server.

    I think this should also be no problem, until a change request from a client actually happens the very time the server also wants to change something. And here we are at my question:

    The whole communication is handled inside the normal event loop. There are no threads. So if the server triggers a change, and just in this exact moment, a change request from a client comes in, will it be either processed before or after the server change, or can it happen that the change request would collide? All changes to the database happen in transactions.

    If all changes are processed one after another, I think it would be enough to check if a change is (still) possible server-side for both local and remote changes. If it's possible, it's applied, and if not, nothing is done and a message is displayed that the change has already been done (either locally or remotely).

    Sorry if this should be a dumb question, but this is something I never did before, and I just don't want to implement stuff in a basically wrong way from the start.

    Thanks for the clarification!

    VRoninV 1 Reply Last reply
    0
    • l3u_L l3u_

      Hi :-)

      I'm writing a program using an SQLite database. It can either start a TCP server or client, so that all connected instances of it (that live on different computers) can broadcast changes and all databases are kept in sync (using the same central database all clients can connect to is not possible/wanted). At least, that's what it should be when I'm finished ;-)

      I already implemented broadcasting all changes that are done on the server instance to all clients. This is no problem and already works.

      But now, it's about how to implement a change coming from a client. I thought about not actually changing anything, but only to send a change request to the server. If everything is fine, the server applies the change and broadcasts it, as it would be done if the change originated from the server.

      I think this should also be no problem, until a change request from a client actually happens the very time the server also wants to change something. And here we are at my question:

      The whole communication is handled inside the normal event loop. There are no threads. So if the server triggers a change, and just in this exact moment, a change request from a client comes in, will it be either processed before or after the server change, or can it happen that the change request would collide? All changes to the database happen in transactions.

      If all changes are processed one after another, I think it would be enough to check if a change is (still) possible server-side for both local and remote changes. If it's possible, it's applied, and if not, nothing is done and a message is displayed that the change has already been done (either locally or remotely).

      Sorry if this should be a dumb question, but this is something I never did before, and I just don't want to implement stuff in a basically wrong way from the start.

      Thanks for the clarification!

      VRoninV Offline
      VRoninV Offline
      VRonin
      wrote on last edited by
      #2

      @l3u_ said in QSqlDatabase using SQlite and timing of concurrent write attempts:

      I thought about not actually changing anything, but only to send a change request to the server. If everything is fine, the server applies the change and broadcasts it, as it would be done if the change originated from the server.

      Good idea.

      There are no threads.

      (I assume this means ther's a single thread) in that case all requests will be managed one after the other. You might have little control on the order of execution but you can be sure there's no chance of 2 things happening at the same time

      "La mort n'est rien, mais vivre vaincu et sans gloire, c'est mourir tous les jours"
      ~Napoleon Bonaparte

      On a crusade to banish setIndexWidget() from the holy land of Qt

      l3u_L kshegunovK 2 Replies Last reply
      1
      • VRoninV VRonin

        @l3u_ said in QSqlDatabase using SQlite and timing of concurrent write attempts:

        I thought about not actually changing anything, but only to send a change request to the server. If everything is fine, the server applies the change and broadcasts it, as it would be done if the change originated from the server.

        Good idea.

        There are no threads.

        (I assume this means ther's a single thread) in that case all requests will be managed one after the other. You might have little control on the order of execution but you can be sure there's no chance of 2 things happening at the same time

        l3u_L Offline
        l3u_L Offline
        l3u_
        wrote on last edited by
        #3

        @VRonin Yes, the program is single-threaded, as well as the handling of client connections. So if I can be sure that each write attempt will be mad one after another, I can simply check if I can do it before I do it. Either, it works and can be done and distributed, or it I can't do it, because it has been done remotely in the very moment the user clicked the "Save" button. This actually should be a rare event, but I definitely have to handle that case.

        Thanks for the clarification :-)

        kshegunovK 1 Reply Last reply
        0
        • l3u_L l3u_

          @VRonin Yes, the program is single-threaded, as well as the handling of client connections. So if I can be sure that each write attempt will be mad one after another, I can simply check if I can do it before I do it. Either, it works and can be done and distributed, or it I can't do it, because it has been done remotely in the very moment the user clicked the "Save" button. This actually should be a rare event, but I definitely have to handle that case.

          Thanks for the clarification :-)

          kshegunovK Offline
          kshegunovK Offline
          kshegunov
          Moderators
          wrote on last edited by kshegunov
          #4

          Threading is a red herring here, you can't run QSqlDatabase from different threads anyway. Your problem is how you can provide atomicity of the operation, correct? Well as it happens I'm working on something remotely similar (at lest the technical infra behind it). So I have decided how I would handle that: tokens.

          An object on the server (doesn't matter if there's a database behind, but let's roll with a db) is assigned a token - that is an identifier of the current state of the object (think of object in this context as a record in the db). So when the client (application) wants to edit something it requests the token for that object from the server, and issues it back alongside with its changes when ready. Now, when the object's updated successfully it's token is re-generated. The idea is that if it so happens that two clients are trying to edit some object on the server, only one of them will succeed, while the server will "know" the other's update request is based on stale data and return back an error message.

          Read and abide by the Qt Code of Conduct

          l3u_L 1 Reply Last reply
          1
          • VRoninV VRonin

            @l3u_ said in QSqlDatabase using SQlite and timing of concurrent write attempts:

            I thought about not actually changing anything, but only to send a change request to the server. If everything is fine, the server applies the change and broadcasts it, as it would be done if the change originated from the server.

            Good idea.

            There are no threads.

            (I assume this means ther's a single thread) in that case all requests will be managed one after the other. You might have little control on the order of execution but you can be sure there's no chance of 2 things happening at the same time

            kshegunovK Offline
            kshegunovK Offline
            kshegunov
            Moderators
            wrote on last edited by
            #5

            @VRonin said in QSqlDatabase using SQlite and timing of concurrent write attempts:

            (I assume this means ther's a single thread) in that case all requests will be managed one after the other. You might have little control on the order of execution but you can be sure there's no chance of 2 things happening at the same time

            That's somewhat misleading, because the network is asynchronous and (quite importantly) has latency. Not everything that is issued from the client happens instantaneously on the server (and vice versa).

            Read and abide by the Qt Code of Conduct

            1 Reply Last reply
            0
            • kshegunovK kshegunov

              Threading is a red herring here, you can't run QSqlDatabase from different threads anyway. Your problem is how you can provide atomicity of the operation, correct? Well as it happens I'm working on something remotely similar (at lest the technical infra behind it). So I have decided how I would handle that: tokens.

              An object on the server (doesn't matter if there's a database behind, but let's roll with a db) is assigned a token - that is an identifier of the current state of the object (think of object in this context as a record in the db). So when the client (application) wants to edit something it requests the token for that object from the server, and issues it back alongside with its changes when ready. Now, when the object's updated successfully it's token is re-generated. The idea is that if it so happens that two clients are trying to edit some object on the server, only one of them will succeed, while the server will "know" the other's update request is based on stale data and return back an error message.

              l3u_L Offline
              l3u_L Offline
              l3u_
              wrote on last edited by l3u_
              #6

              @kshegunov It's actually about atomic operations. But I think if all write attempts happen one after another, I think I'm safe by always checking if the requested change is possible, am I?

              Example:

              We have a name entry "foo". The server wants to change it to "bar". The client wants to change it to "whatever". And these two requests happen at the very same time. Now, there are two possibilities:

              The server request happens first. I check if we have a "foo" name entry. It's there, and I change it to "bar". Then, the client request is processed. I check if there is a "foo" entry, but there is none – so I tell the client that the change is no more possible and do nothing.

              Same for the other order: If the client request is processed first, "foo" is renamed to "whatever", and the server request will fail, because there's no more "foo" name.

              Or am I wrong here?!

              kshegunovK 1 Reply Last reply
              0
              • l3u_L l3u_

                @kshegunov It's actually about atomic operations. But I think if all write attempts happen one after another, I think I'm safe by always checking if the requested change is possible, am I?

                Example:

                We have a name entry "foo". The server wants to change it to "bar". The client wants to change it to "whatever". And these two requests happen at the very same time. Now, there are two possibilities:

                The server request happens first. I check if we have a "foo" name entry. It's there, and I change it to "bar". Then, the client request is processed. I check if there is a "foo" entry, but there is none – so I tell the client that the change is no more possible and do nothing.

                Same for the other order: If the client request is processed first, "foo" is renamed to "whatever", and the server request will fail, because there's no more "foo" name.

                Or am I wrong here?!

                kshegunovK Offline
                kshegunovK Offline
                kshegunov
                Moderators
                wrote on last edited by kshegunov
                #7

                @l3u_ said in QSqlDatabase using SQlite and timing of concurrent write attempts:

                Or am I wrong here?!

                No, you are correct, and this is indeed the way to do it. I was just trying to provide additional "insight", rather clumsily. In my program the data is entered by people (users), so for me it's not enough simply to tell the user "Sorry dude, somebody beat you to it". I'd have to provide some means for the user to reload the whole piece of data, which can consist of multiple fields. As I'm sending the messages as a whole I'd want to check if any of the fields (i.e. any part of the DB record) got changed in the mean time, not only one single string, or an integer.

                Read and abide by the Qt Code of Conduct

                l3u_L 1 Reply Last reply
                1
                • kshegunovK kshegunov

                  @l3u_ said in QSqlDatabase using SQlite and timing of concurrent write attempts:

                  Or am I wrong here?!

                  No, you are correct, and this is indeed the way to do it. I was just trying to provide additional "insight", rather clumsily. In my program the data is entered by people (users), so for me it's not enough simply to tell the user "Sorry dude, somebody beat you to it". I'd have to provide some means for the user to reload the whole piece of data, which can consist of multiple fields. As I'm sending the messages as a whole I'd want to check if any of the fields (i.e. any part of the DB record) got changed in the mean time, not only one single string, or an integer.

                  l3u_L Offline
                  l3u_L Offline
                  l3u_
                  wrote on last edited by
                  #8

                  @kshegunov Okay, nice! Luckily, in my case, I actually can say "bad luck, dude, somebody already changed it" ;-)

                  1 Reply Last reply
                  0
                  • SGaistS Offline
                    SGaistS Offline
                    SGaist
                    Lifetime Qt Champion
                    wrote on last edited by
                    #9

                    Hi,

                    Out of curiosity, why not use a database system that already does that kind of things ? Like a PostgreSQL cluster

                    @kshegunov IIRC, you can use QSqlDatabase in a multi-threaded setup however, each thread must have its own connection to the database.

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    kshegunovK l3u_L 2 Replies Last reply
                    0
                    • SGaistS SGaist

                      Hi,

                      Out of curiosity, why not use a database system that already does that kind of things ? Like a PostgreSQL cluster

                      @kshegunov IIRC, you can use QSqlDatabase in a multi-threaded setup however, each thread must have its own connection to the database.

                      kshegunovK Offline
                      kshegunovK Offline
                      kshegunov
                      Moderators
                      wrote on last edited by
                      #10

                      @SGaist said in QSqlDatabase using SQlite and timing of concurrent write attempts:

                      @kshegunov IIRC, you can use QSqlDatabase in a multi-threaded setup however, each thread must have its own connection to the database.

                      Yes, this is exactly what I meant. By the way from, the point of view of the database two connections might as well be 2 separate clients.

                      Read and abide by the Qt Code of Conduct

                      1 Reply Last reply
                      0
                      • SGaistS SGaist

                        Hi,

                        Out of curiosity, why not use a database system that already does that kind of things ? Like a PostgreSQL cluster

                        @kshegunov IIRC, you can use QSqlDatabase in a multi-threaded setup however, each thread must have its own connection to the database.

                        l3u_L Offline
                        l3u_L Offline
                        l3u_
                        wrote on last edited by
                        #11

                        @SGaist It's a special case ;-)

                        It's about a program to manage tournaments for a card game. For a normal tournament, it's completely sufficient to have one notebook to manage the registration. For a big tournament, it's nice to have two laptops to registrate people so that the queue won't grow too long.

                        What I'm doing is a simple network connection so that the registration computers can talk to each other and everybody has the current list of participants.

                        It's important that the program stays as simple to use as it is at the moment. With SQLite as the backend, it just works out of the box. Nobody using it would want to or even be able to setup a database server before using it.

                        1 Reply Last reply
                        0

                        • Login

                        • Login or register to search.
                        • First post
                          Last post
                        0
                        • Categories
                        • Recent
                        • Tags
                        • Popular
                        • Users
                        • Groups
                        • Search
                        • Get Qt Extensions
                        • Unsolved