2
2
3
3
import java .io .IOException ;
4
4
import java .nio .file .Files ;
5
+ import java .nio .file .Path ;
5
6
import java .nio .file .Paths ;
6
7
import java .nio .file .StandardCopyOption ;
7
8
import java .sql .SQLException ;
8
9
import java .util .concurrent .TimeUnit ;
9
10
import java .util .concurrent .atomic .AtomicBoolean ;
10
11
11
- import jakarta .enterprise . context . ApplicationScoped ;
12
+ import jakarta .annotation . PostConstruct ;
12
13
import jakarta .enterprise .event .Observes ;
13
14
import jakarta .inject .Inject ;
15
+ import jakarta .inject .Singleton ;
14
16
import jakarta .persistence .EntityManager ;
15
17
16
18
import org .eclipse .microprofile .config .inject .ConfigProperty ;
17
19
import org .hibernate .engine .jdbc .connections .spi .JdbcConnectionAccess ;
18
20
import org .hibernate .internal .SessionImpl ;
19
- import org .jboss .logging .Logger ;
20
21
22
+ import io .quarkus .logging .Log ;
21
23
import io .quarkus .runtime .ShutdownEvent ;
22
24
import io .quarkus .scheduler .Scheduled ;
23
25
24
- @ ApplicationScoped
26
+ @ Singleton
25
27
public class SQLiteFilePersister {
28
+ private final AtomicBoolean executing = new AtomicBoolean (false );
26
29
@ ConfigProperty (name = "quarkus.datasource.jdbc.url" )
27
30
String jdbcUrl ;
28
-
29
- private static final Logger LOGGER = Logger .getLogger (SQLiteFilePersister .class .getName ());
30
-
31
31
@ Inject
32
32
EntityManager entityManager ;
33
+ private Path dbFile ;
34
+ private Path backupDBFile ;
35
+ private JdbcConnectionAccess access ;
33
36
34
- private final AtomicBoolean executing = new AtomicBoolean (false );
37
+ @ PostConstruct
38
+ void init () {
39
+ int prefixLength = "jdbc:sqlite:" .length ();
40
+ int queryParamsIdx = jdbcUrl .indexOf ('?' );
41
+ int length = (queryParamsIdx != -1 ) ? queryParamsIdx : jdbcUrl .length ();
42
+ var dbFileName = jdbcUrl .substring (prefixLength , length );
43
+ dbFile = Paths .get (dbFileName );
44
+ backupDBFile = dbFile .toAbsolutePath ().getParent ().resolve (dbFile .getFileName () + "_backup" );
45
+ access = entityManager .unwrap (SessionImpl .class ).getJdbcConnectionAccess ();
46
+ }
35
47
36
48
// Execute a backup every 10 seconds
37
49
@ Scheduled (delay = 10 , delayUnit = TimeUnit .SECONDS , every = "10s" )
@@ -47,37 +59,24 @@ public void onShutdown(@Observes ShutdownEvent event) {
47
59
void backup () {
48
60
if (executing .compareAndSet (false , true )) {
49
61
try {
50
- int prefixLength = "jdbc:sqlite:" .length ();
51
- int queryParamsIdx = jdbcUrl .indexOf ('?' );
52
- int length = (queryParamsIdx != -1 ) ? queryParamsIdx : jdbcUrl .length ();
53
- String dbFile = jdbcUrl .substring (prefixLength , length );
54
-
55
- var originalDbFilePath = Paths .get (dbFile );
56
- LOGGER .info ("Starting DB backup for file: " + dbFile );
57
- var backupDbFilePath = originalDbFilePath .toAbsolutePath ().getParent ()
58
- .resolve (originalDbFilePath .getFileName () + "_backup" );
59
-
60
- JdbcConnectionAccess access = entityManager
61
- .unwrap (SessionImpl .class )
62
- .getJdbcConnectionAccess ();
62
+ Log .trace ("Starting DB backup for file: " + dbFile );
63
63
try (var conn = access .obtainConnection ();
64
64
var stmt = conn .createStatement ()) {
65
65
// Execute the backup
66
- stmt .executeUpdate ("backup to " + backupDbFilePath );
66
+ stmt .executeUpdate ("backup to " + backupDBFile );
67
67
// Atomically substitute the DB file with its backup
68
- Files .move (backupDbFilePath , originalDbFilePath , StandardCopyOption .ATOMIC_MOVE ,
69
- StandardCopyOption .REPLACE_EXISTING );
68
+ Files .move (backupDBFile , dbFile , StandardCopyOption .ATOMIC_MOVE , StandardCopyOption .REPLACE_EXISTING );
70
69
} catch (SQLException e ) {
71
70
throw new RuntimeException ("Failed to backup the database" , e );
72
71
} catch (IOException e ) {
73
72
throw new RuntimeException ("Failed to create backup files or folders" , e );
74
73
}
75
- LOGGER .info ("Backup of " + dbFile + " completed. " );
74
+ Log .info ("Backup of " + dbFile + " completed" );
76
75
} finally {
77
76
executing .set (false );
78
77
}
79
78
} else {
80
- LOGGER . info ( "Backup in progress. " );
79
+ Log . trace ( "Skipping backup as one is already in progress" );
81
80
}
82
81
}
83
82
0 commit comments