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. Monitoring an SQLite database with QFileSystemWatcher does not work as expected
Forum Updated to NodeBB v4.3 + New Features

Monitoring an SQLite database with QFileSystemWatcher does not work as expected

Scheduled Pinned Locked Moved Solved General and Desktop
28 Posts 5 Posters 4.7k Views 2 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.
  • M Offline
    M Offline
    mrjj
    Lifetime Qt Champion
    wrote on 30 May 2018, 13:55 last edited by
    #6

    Hi
    Do you simply what to know if it was changed from outside ?
    Other uses cases is to prevent it and using encryption can be one way
    https://stackoverflow.com/questions/5669905/sqlite-with-encryption-password-protection/5877130#5877130

    1 Reply Last reply
    0
    • L Offline
      L Offline
      l3u_
      wrote on 30 May 2018, 14:03 last edited by
      #7

      It's not about preventing malicious changes. It's simply about "The user accidentally deletes the database file while the program runs and then it behaves not as expected". I just want to popup a warning "The file has been changed, possibly it's broken now, you better reload it" or "Write access has been removed, can only display from now, not change anymore".

      M 1 Reply Last reply 30 May 2018, 14:13
      0
      • P Paul Colby
        30 May 2018, 13:44

        @JonB said in Monitoring an SQLite database with QFileSystemWatcher does not work as expected:

        I assumed it used the native facilities from the OS....

        It can, but it depends on the OS. It will, for example, use inotify where possible (and considered reliable), which doesn't require polling, but does poll in lots of other cases.

        See QFileSystemWatcherPrivate::createNativeEngine() for some of the engines that might be used.

        Cheers.

        J Offline
        J Offline
        JonB
        wrote on 30 May 2018, 14:09 last edited by
        #8

        @Paul-Colby
        But that doesn't sound like @VRonin 's

        QFileSystemWatcher works with polling. It has a timer internally that every second will check the paths you added and store the values. Then, after 1 second, it will check again and if they are different it will trigger the signal.

        hence my comment.

        1 Reply Last reply
        0
        • L l3u_
          30 May 2018, 14:03

          It's not about preventing malicious changes. It's simply about "The user accidentally deletes the database file while the program runs and then it behaves not as expected". I just want to popup a warning "The file has been changed, possibly it's broken now, you better reload it" or "Write access has been removed, can only display from now, not change anymore".

          M Offline
          M Offline
          mrjj
          Lifetime Qt Champion
          wrote on 30 May 2018, 14:13 last edited by
          #9

          @l3u_
          Hi
          ok. so its just to know.
          What about using Exclusive file locking mode
          http://www.sqlite.org/pragma.html#pragma_locking_mode
          Your process will then own the file and user cannot delete it.
          Or at least it used to work that way. Disclaimer. Not tested/used recently.

          L 1 Reply Last reply 30 May 2018, 14:45
          0
          • M mrjj
            30 May 2018, 14:13

            @l3u_
            Hi
            ok. so its just to know.
            What about using Exclusive file locking mode
            http://www.sqlite.org/pragma.html#pragma_locking_mode
            Your process will then own the file and user cannot delete it.
            Or at least it used to work that way. Disclaimer. Not tested/used recently.

            L Offline
            L Offline
            l3u_
            wrote on 30 May 2018, 14:45 last edited by
            #10

            @mrjj Hey, that sounds good :-) Executing the following statements (I suppose there's no QSqlDatabase function for that like QSqlDatabase::transaction()?!)

            PRAGMA locking_mode = EXCLUSIVE
            BEGIN EXCLUSIVE
            COMMIT
            

            actually causes another connection to be read-only, if one wants to change something, one gets an error "database is busy". Nice! This prevents the database to be (accidentally) changed by another process (e. g. two instances of my program opening the same database).

            The thing that's left is to know if the user move or deleted the database or changed permissions during runtime …

            M 1 Reply Last reply 30 May 2018, 15:05
            0
            • L l3u_
              30 May 2018, 14:45

              @mrjj Hey, that sounds good :-) Executing the following statements (I suppose there's no QSqlDatabase function for that like QSqlDatabase::transaction()?!)

              PRAGMA locking_mode = EXCLUSIVE
              BEGIN EXCLUSIVE
              COMMIT
              

              actually causes another connection to be read-only, if one wants to change something, one gets an error "database is busy". Nice! This prevents the database to be (accidentally) changed by another process (e. g. two instances of my program opening the same database).

              The thing that's left is to know if the user move or deleted the database or changed permissions during runtime …

              M Offline
              M Offline
              mrjj
              Lifetime Qt Champion
              wrote on 30 May 2018, 15:05 last edited by
              #11

              @l3u_
              Hi so even in EXCLUSIVE mode, the actual file is not locked on OS level?
              Like you can rename or move it.
              Hmm, i guess i recall incorrectly then.

              L 1 Reply Last reply 30 May 2018, 22:50
              0
              • M mrjj
                30 May 2018, 15:05

                @l3u_
                Hi so even in EXCLUSIVE mode, the actual file is not locked on OS level?
                Like you can rename or move it.
                Hmm, i guess i recall incorrectly then.

                L Offline
                L Offline
                l3u_
                wrote on 30 May 2018, 22:50 last edited by
                #12

                @mrjj I can do what I want on filesystem level. It's protected against changes by another SQLite connection though.

                J 1 Reply Last reply 31 May 2018, 08:27
                0
                • P Paul Colby
                  30 May 2018, 13:44

                  @JonB said in Monitoring an SQLite database with QFileSystemWatcher does not work as expected:

                  I assumed it used the native facilities from the OS....

                  It can, but it depends on the OS. It will, for example, use inotify where possible (and considered reliable), which doesn't require polling, but does poll in lots of other cases.

                  See QFileSystemWatcherPrivate::createNativeEngine() for some of the engines that might be used.

                  Cheers.

                  V Offline
                  V Offline
                  VRonin
                  wrote on 31 May 2018, 07:13 last edited by
                  #13

                  @Paul-Colby said in Monitoring an SQLite database with QFileSystemWatcher does not work as expected:

                  It can, but it depends on the OS. It will, for example, use inotify where possible

                  Just to be clearer, even if inotify is used the event will be processed only when control goes back to the event loop so my code above can be considered safer when using inotify as it reduces the delay (from up to 1sec to the time it takes your program to reach the event loop)

                  "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

                  1 Reply Last reply
                  0
                  • L l3u_
                    30 May 2018, 22:50

                    @mrjj I can do what I want on filesystem level. It's protected against changes by another SQLite connection though.

                    J Offline
                    J Offline
                    JonB
                    wrote on 31 May 2018, 08:27 last edited by
                    #14

                    @l3u_
                    I don't really know what you expect to achieve realistically.

                    It's not clear to me from http://www.sqlite.org/pragma.html#pragma_locking_mode just exactly what they mean by "exclusive". It may only mean that the locks are respected by other SQLite processes, not the OS, and your findings seem to indicate that. Or, it may be that behaviour varies by OS, e.g. locked by OS under Windows but not under Linux.

                    QFileSystemWatcher is not designed to play along with "I want to know which process made a change, and ignore if it's mine". I don't think you (or it) will have any access to that in information.

                    The thing that's left is to know if the user move or deleted the database or changed permissions during runtime …

                    In any case, these may not act as you think they will act, e.g.:

                    • In Linux certainly (can't remember about Windows), one process can delete a file. If another process has that file open at present, the file is marked for deletion, but not actually deleted till all processes with it open close their connections. (And I don't think your QFileSystemWatcher will notice till it actually gets deleted.)

                    • When permissions on a file are changed to prevent access, these new permissions have no effect on processes which presently have a handle open on the file, only on processes newly trying to open the file. SQLite presumably holds open handles on the database files all the time, so will carry on as before.

                    • Even with OS locking of file content, that may well not have any effect on any attempt to delete/rename/change permissions on the file itself.

                    L 1 Reply Last reply 31 May 2018, 17:30
                    0
                    • J JonB
                      31 May 2018, 08:27

                      @l3u_
                      I don't really know what you expect to achieve realistically.

                      It's not clear to me from http://www.sqlite.org/pragma.html#pragma_locking_mode just exactly what they mean by "exclusive". It may only mean that the locks are respected by other SQLite processes, not the OS, and your findings seem to indicate that. Or, it may be that behaviour varies by OS, e.g. locked by OS under Windows but not under Linux.

                      QFileSystemWatcher is not designed to play along with "I want to know which process made a change, and ignore if it's mine". I don't think you (or it) will have any access to that in information.

                      The thing that's left is to know if the user move or deleted the database or changed permissions during runtime …

                      In any case, these may not act as you think they will act, e.g.:

                      • In Linux certainly (can't remember about Windows), one process can delete a file. If another process has that file open at present, the file is marked for deletion, but not actually deleted till all processes with it open close their connections. (And I don't think your QFileSystemWatcher will notice till it actually gets deleted.)

                      • When permissions on a file are changed to prevent access, these new permissions have no effect on processes which presently have a handle open on the file, only on processes newly trying to open the file. SQLite presumably holds open handles on the database files all the time, so will carry on as before.

                      • Even with OS locking of file content, that may well not have any effect on any attempt to delete/rename/change permissions on the file itself.

                      L Offline
                      L Offline
                      l3u_
                      wrote on 31 May 2018, 17:30 last edited by
                      #15

                      @JonB said in Monitoring an SQLite database with QFileSystemWatcher does not work as expected:

                      @l3u_
                      I don't really know what you expect to achieve realistically.

                      The idea is quite simple. The database is not intended to be accessed by multiple processes. So if another process changes something while the program runs, it's possible that it breaks. By setting "locking_mode", I can prevent such changes, as simply the database can't be used by any other connection until it's closed. That's one thing I wanted (and achieved in an elegant way I think, as both my program does handle such a lock now, and e. g. a manual cli connection also refuses to work on the database as long as it's open).

                      The other thing is to inform the user if e. g. the file has been accidentally deleted while it's open. By now, the program doesn't know it, and on the next change, all data is gone without an error message, which is imo not a desirable behavior. Instead, an error should pop up saying something like "The database file has been deleted, so we reset our program as if we closed it now".

                      And this is probably possible by monitoring it via a QFileSystemWatcher, isn't it? If I check if it's still there on each change, I know if it was deleted and can handle this.

                      J 1 Reply Last reply 31 May 2018, 18:21
                      0
                      • V Offline
                        V Offline
                        VRonin
                        wrote on 31 May 2018, 17:48 last edited by
                        #16

                        Just throwing an idea out there: Qt Creator does this for source files so you should be able to check the source of Qt Creator and find the perfect solution to your problem

                        "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

                        1 Reply Last reply
                        3
                        • L l3u_
                          31 May 2018, 17:30

                          @JonB said in Monitoring an SQLite database with QFileSystemWatcher does not work as expected:

                          @l3u_
                          I don't really know what you expect to achieve realistically.

                          The idea is quite simple. The database is not intended to be accessed by multiple processes. So if another process changes something while the program runs, it's possible that it breaks. By setting "locking_mode", I can prevent such changes, as simply the database can't be used by any other connection until it's closed. That's one thing I wanted (and achieved in an elegant way I think, as both my program does handle such a lock now, and e. g. a manual cli connection also refuses to work on the database as long as it's open).

                          The other thing is to inform the user if e. g. the file has been accidentally deleted while it's open. By now, the program doesn't know it, and on the next change, all data is gone without an error message, which is imo not a desirable behavior. Instead, an error should pop up saying something like "The database file has been deleted, so we reset our program as if we closed it now".

                          And this is probably possible by monitoring it via a QFileSystemWatcher, isn't it? If I check if it's still there on each change, I know if it was deleted and can handle this.

                          J Offline
                          J Offline
                          JonB
                          wrote on 31 May 2018, 18:21 last edited by
                          #17

                          @l3u_
                          As I tried to show in examples, I do not believe you can reliably achieve what you would like to achieve, at least not cross-platform.

                          L 1 Reply Last reply 1 Jun 2018, 15:10
                          0
                          • L Offline
                            L Offline
                            l3u_
                            wrote on 31 May 2018, 18:39 last edited by
                            #18

                            As far as I can see, they also use a QFileSystemWatcher to handle this kind of changes.

                            1 Reply Last reply
                            0
                            • J JonB
                              31 May 2018, 18:21

                              @l3u_
                              As I tried to show in examples, I do not believe you can reliably achieve what you would like to achieve, at least not cross-platform.

                              L Offline
                              L Offline
                              l3u_
                              wrote on 1 Jun 2018, 15:10 last edited by l3u_ 6 Jan 2018, 16:54
                              #19

                              @JonB Apart from the change protection (changes by accident by opening the same database with two program instances), I'm actually only interested in knowing if the file has been deleted during runtime … Should I simply let a QFileSystemWatcher watch it an check it's still there after each change? Or is this the wrong way?

                              J 1 Reply Last reply 1 Jun 2018, 17:42
                              0
                              • L l3u_
                                1 Jun 2018, 15:10

                                @JonB Apart from the change protection (changes by accident by opening the same database with two program instances), I'm actually only interested in knowing if the file has been deleted during runtime … Should I simply let a QFileSystemWatcher watch it an check it's still there after each change? Or is this the wrong way?

                                J Offline
                                J Offline
                                JonB
                                wrote on 1 Jun 2018, 17:42 last edited by
                                #20

                                @l3u_
                                I have said, I'm not convinced it will work in this circumstance, at least under Linux, and I still don't think you've said which OS you're under. But why don't you first test the situation: run up your database Qt app, then go separately try to delete the file and see whether you can? If you can, test to see if QFileSystemWatcher detects it correctly.

                                I don't think you "let a QFileSystemWatcher watch it an check it's still there after each change". You set up a QFileSystemWatcher, then it will signal you on file delete. Rather than you do any checking at certain periods yourself.

                                L 1 Reply Last reply 1 Jun 2018, 18:43
                                0
                                • J JonB
                                  1 Jun 2018, 17:42

                                  @l3u_
                                  I have said, I'm not convinced it will work in this circumstance, at least under Linux, and I still don't think you've said which OS you're under. But why don't you first test the situation: run up your database Qt app, then go separately try to delete the file and see whether you can? If you can, test to see if QFileSystemWatcher detects it correctly.

                                  I don't think you "let a QFileSystemWatcher watch it an check it's still there after each change". You set up a QFileSystemWatcher, then it will signal you on file delete. Rather than you do any checking at certain periods yourself.

                                  L Offline
                                  L Offline
                                  l3u_
                                  wrote on 1 Jun 2018, 18:43 last edited by
                                  #21

                                  @JonB I'm on Linux and also compile the program on Windows. And, at least on Linux, I can delete the file while it's open.

                                  The QFileSystemWatcher won't only signal me on file delete, but on each change, won't it? So I will have to find out if the file has been deleted on each change, won't I?

                                  J 1 Reply Last reply 1 Jun 2018, 19:03
                                  0
                                  • L l3u_
                                    1 Jun 2018, 18:43

                                    @JonB I'm on Linux and also compile the program on Windows. And, at least on Linux, I can delete the file while it's open.

                                    The QFileSystemWatcher won't only signal me on file delete, but on each change, won't it? So I will have to find out if the file has been deleted on each change, won't I?

                                    J Offline
                                    J Offline
                                    JonB
                                    wrote on 1 Jun 2018, 19:03 last edited by
                                    #22

                                    @l3u_

                                    I'm on Linux and also compile the program on Windows. And, at least on Linux, I can delete the file while it's open.

                                    I expected that. But I'm saying: in that situation, have you actually tested whether your QFileSystemWatcher signals you that's it's been deleted (while you still have the database open)? I'm not sure it will, you need to check.

                                    So I will have to find out if the file has been deleted on each change, won't I?

                                    I had thought you made "on each change you make to the database". Now I think you mean "on each change signalled by QFileSystemWatcher".

                                    void QFileSystemWatcher::fileChanged(const QString &path)¶
                                    This signal is emitted when the file at the specified path is modified, renamed or removed from disk.

                                    Yes, that's all you get. So you would have to check whether the file still exists. Don't do that too often!

                                    Worse, I presume this means you'll get signalled when you make changes to your own database file.

                                    Like I said, you now need to try a bit of code to see when you do & do not get these file notification messages.

                                    L 1 Reply Last reply 1 Jun 2018, 19:42
                                    0
                                    • J JonB
                                      1 Jun 2018, 19:03

                                      @l3u_

                                      I'm on Linux and also compile the program on Windows. And, at least on Linux, I can delete the file while it's open.

                                      I expected that. But I'm saying: in that situation, have you actually tested whether your QFileSystemWatcher signals you that's it's been deleted (while you still have the database open)? I'm not sure it will, you need to check.

                                      So I will have to find out if the file has been deleted on each change, won't I?

                                      I had thought you made "on each change you make to the database". Now I think you mean "on each change signalled by QFileSystemWatcher".

                                      void QFileSystemWatcher::fileChanged(const QString &path)¶
                                      This signal is emitted when the file at the specified path is modified, renamed or removed from disk.

                                      Yes, that's all you get. So you would have to check whether the file still exists. Don't do that too often!

                                      Worse, I presume this means you'll get signalled when you make changes to your own database file.

                                      Like I said, you now need to try a bit of code to see when you do & do not get these file notification messages.

                                      L Offline
                                      L Offline
                                      l3u_
                                      wrote on 1 Jun 2018, 19:42 last edited by
                                      #23

                                      @JonB said in Monitoring an SQLite database with QFileSystemWatcher does not work as expected:

                                      Worse, I presume this means you'll get signalled when you make changes to your own database file.

                                      Yes, and that's the problem – I already tried to setup a QFileSystemWatcher and silent it when I do changes myself (because I'm only interested in changes done outside the scope of my program cf. my initial post!), but that didn't work as expected.

                                      And now I'm, not sure if using it is the right way for a case that won't happen very often. I mean if e. g. KWrite sets up a QFileSystemWatcher, the only case it will receive a signal is when something else modified or deleted the file, because it lives and is modified in KWrite's cache, not on disk. But I work on the database directly, so it's changed with each INSERT or UPDATE statement …

                                      J 1 Reply Last reply 1 Jun 2018, 20:00
                                      0
                                      • L l3u_
                                        1 Jun 2018, 19:42

                                        @JonB said in Monitoring an SQLite database with QFileSystemWatcher does not work as expected:

                                        Worse, I presume this means you'll get signalled when you make changes to your own database file.

                                        Yes, and that's the problem – I already tried to setup a QFileSystemWatcher and silent it when I do changes myself (because I'm only interested in changes done outside the scope of my program cf. my initial post!), but that didn't work as expected.

                                        And now I'm, not sure if using it is the right way for a case that won't happen very often. I mean if e. g. KWrite sets up a QFileSystemWatcher, the only case it will receive a signal is when something else modified or deleted the file, because it lives and is modified in KWrite's cache, not on disk. But I work on the database directly, so it's changed with each INSERT or UPDATE statement …

                                        J Offline
                                        J Offline
                                        JonB
                                        wrote on 1 Jun 2018, 20:00 last edited by
                                        #24

                                        @l3u_
                                        Which is why I wouldn't be doing any of this file watching stuff.

                                        L 1 Reply Last reply 1 Jun 2018, 20:17
                                        0
                                        • J JonB
                                          1 Jun 2018, 20:00

                                          @l3u_
                                          Which is why I wouldn't be doing any of this file watching stuff.

                                          L Offline
                                          L Offline
                                          l3u_
                                          wrote on 1 Jun 2018, 20:17 last edited by
                                          #25

                                          @JonB Most probably, it's simply the wrong approach at all when using an SQLite database …

                                          Perhaps, I should create a copy of the original database in a temporary location, work on this one and copy it back if the user "saves".

                                          Apparently, it's also possible to read an on-disk database to a :memory: database and back using SQLite's backup mechanism … this way, one could work on in-memory data without having to mess with the user or other processes changing the data. But this doesn't seem to be too easy, at least, it's not supported by Qt functions.

                                          Well, let's see if and how this can be solved …

                                          J 1 Reply Last reply 1 Jun 2018, 20:21
                                          0

                                          15/28

                                          31 May 2018, 17:30

                                          • Login

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