Megatest

Check-in [a82e2bb971]
Login
Overview
Comment:no-sync db and db open locking working.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | v1.7001-multi-db-wip2 | v1.7001-multi-db-rb01
Files: files | file ages | folders
SHA1: a82e2bb971ae4bd7f6adf5d9f1af00ae53ea99ce
User & Date: matt on 2022-04-12 07:15:00
Other Links: branch diff | manifest | tags
Context
2022-04-12
07:15
Merged back to v1.7001-multi-db check-in: 689ac0bf5f user: matt tags: v1.7001-multi-db-rb01
07:15
no-sync db and db open locking working. Closed-Leaf check-in: a82e2bb971 user: matt tags: v1.7001-multi-db-wip2, v1.7001-multi-db-rb01
2022-04-11
21:43
wip check-in: bd65c1e661 user: matt tags: v1.7001-multi-db-wip2, v1.7001-multi-db-rb01
Changes

Modified dbfile.scm from [13bb3140b5] to [ece2b4a17f].

16
17
18
19
20
21
22

23
24
25
26
27
28
29
30
31
32
33


34
35
36
37
38
39
40
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43







+











+
+







;;     You should have received a copy of the GNU General Public License
;;     along with Megatest.  If not, see <http://www.gnu.org/licenses/>.

;;======================================================================

(declare (unit dbfile))
;; (declare (uses debugprint))
;; (declare (uses commonmod))

(module dbfile
	*
	
(import scheme chicken data-structures extras)
(import (prefix sqlite3 sqlite3:)
	posix typed-records srfi-18
	srfi-69
	stack
	files
	ports

	;; commonmod
	)

;; (import debugprint)

;;======================================================================
;;  R E C O R D S
;;======================================================================
266
267
268
269
270
271
272
273

274
275
276
277



278
279
280
281
282
283
284
285
286
287
288
289
290
291
269
270
271
272
273
274
275

276




277
278
279







280
281
282
283
284
285
286







-
+
-
-
-
-
+
+
+
-
-
-
-
-
-
-








;; Open the classic megatest.db file (defaults to open in toppath)
;;
;;   NOTE: returns a dbdat not a dbstruct!
;;
(define (dbfile:open-sqlite3-db dbpath init-proc)
  (let* ((dbexists     (file-exists? dbpath))
	 (db           ;; need locking here so multiple open
	 (write-access (file-write-access? dbpath))
	               ;; do not collide
	  (let* ((db (sqlite3:open-database dbpath)))
	    (sqlite3:set-busy-handler! db (sqlite3:make-busy-timeout 10000))
	    (init-proc db))
	 (db           (dbfile:cautious-open-database dbpath))) #;(sqlite3:open-database dbpath)
    (sqlite3:set-busy-handler! db (sqlite3:make-busy-timeout 10000))
    (init-proc db)
	  #;(dbfile:lock-create-open dbpath
	  (lambda (db)
	  (init-proc db))))
	 (write-access (file-write-access? dbpath)))
    #;(if (and dbexists (not write-access))
	(set! *db-write-access* #f))
    ;; (cons db dbpath)))
    (make-dbr:dbdat dbfile: dbpath dbh: db read-only: (not write-access))))

(define (dbfile:print-and-exit . params)
  (with-output-to-port
      (current-error-port)
    (lambda ()
      (apply print params)))
444
445
446
447
448
449
450

451
452


453
454






455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472




















473
474
475



476
477
478
479
480
481
482
483
484
485
486
487













488
489
490
491
492
493
494
439
440
441
442
443
444
445
446


447
448
449
450
451
452
453
454
455
456


















457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482












483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502







+
-
-
+
+


+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+



+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+








;; if we are not a server create a db handle. this is not finalized
;; so watch for problems. I'm still not clear if it is needed to manually
;; finalize sqlite3 dbs with the sqlite3 egg.
;;

(define (dbfile:cautious-open-database fname #!optional (tries-left 5))
  (let* ((lock-file (conc fname".lock"))
  (let* ((retry (lambda ()
		  (thread-sleep! 0.5)
	 (retry (lambda ()
		  (thread-sleep! 1.1)
		  (if (> tries-left 0)
		      (dbfile:cautious-open-database fname (- tries-left 1))))))
    (assert (>= tries-left 0) (conc "FATAL: Five attempts in dbfile:cautious-open-database of "fname", giving up."))
    (if (not (dbfile:simple-file-lock lock-file))
	(begin
	  (dbfile:print-err "INFO: lock file "lock-file" exists, trying again in 3 seconds.")
	  (thread-sleep! 3)
	  (dbfile:cautious-open-database fname (- tries-left 1)))
    (condition-case
	(sqlite3:open-database fname)
      (exn (io-error)
	   (dbfile:print-err exn "ERROR: i/o error with " fname ". Check permissions, disk space etc. and try again.")
	   (retry))
      (exn (corrupt)
	   (dbfile:print-err exn "ERROR: database " fname " is corrupt. Repair it to proceed.")
	   (retry))
      (exn (busy)
	   (dbfile:print-err exn "ERROR: database " fname
			     " is locked. Try copying to another location, remove original and copy back.")
	   (retry))
      (exn (permission)(dbfile:print-err exn "ERROR: database " fname " has some permissions problem.")
	   (retry))
      (exn ()
	   (dbfile:print-err exn "ERROR: Unknown error with database " fname " message: "
			     ((condition-property-accessor 'exn 'message) exn))
	   (retry)))))
	(let ((result (condition-case
			  (sqlite3:open-database fname)
			(exn (io-error)
			     (dbfile:print-err exn "ERROR: i/o error with " fname ". Check permissions, disk space etc. and try again.")
			     (retry))
			(exn (corrupt)
			     (dbfile:print-err exn "ERROR: database " fname " is corrupt. Repair it to proceed.")
			     (retry))
			(exn (busy)
			     (dbfile:print-err exn "ERROR: database " fname
					       " is locked. Try copying to another location, remove original and copy back.")
			     (retry))
			(exn (permission)(dbfile:print-err exn "ERROR: database " fname " has some permissions problem.")
			     (retry))
			(exn ()
			     (dbfile:print-err exn "ERROR: Unknown error with database " fname " message: "
					       ((condition-property-accessor 'exn 'message) exn))
			     (retry)))))
	  (dbfile:simple-file-release-lock lock-file)
	  result))))


(define (dbfile:open-no-sync-db dbpath)
  (if *no-sync-db*
      *no-sync-db*
      (begin
  (if (not (file-exists? dbpath))
      (create-directory dbpath #t))
  (let* ((dbname    (conc dbpath "/no-sync.db"))
	 (db-exists (file-exists? dbname))
	 (db        (dbfile:cautious-open-database dbname))) ;; (sqlite3:open-database dbname)))
    (sqlite3:set-busy-handler! db (sqlite3:make-busy-timeout 136000))
    (if (not db-exists)
	(begin
	  (sqlite3:execute db "PRAGMA synchronous = 0;")
	  (sqlite3:execute db "CREATE TABLE IF NOT EXISTS no_sync_metadat (var TEXT,val TEXT, CONSTRAINT no_sync_metadat_constraint UNIQUE (var));")
	  #;(sqlite3:execute db "PRAGMA journal_mode=WAL;")))
    db))
	(if (not (file-exists? dbpath))
	    (create-directory dbpath #t))
	(let* ((dbname    (conc dbpath "/no-sync.db"))
	       (db-exists (file-exists? dbname))
	       (db        (dbfile:cautious-open-database dbname))) ;; (sqlite3:open-database dbname)))
	  (sqlite3:set-busy-handler! db (sqlite3:make-busy-timeout 136000))
	  (if (not db-exists)
	      (begin
		(sqlite3:execute db "PRAGMA synchronous = 0;")
		(sqlite3:execute db "CREATE TABLE IF NOT EXISTS no_sync_metadat (var TEXT,val TEXT, CONSTRAINT no_sync_metadat_constraint UNIQUE (var));")
		#;(sqlite3:execute db "PRAGMA journal_mode=WAL;")))
	  (set! *no-sync-db* db)
	  db))))

(define (db:no-sync-set db var val)
  (sqlite3:execute db "INSERT OR REPLACE INTO no_sync_metadat (var,val) VALUES (?,?);" var val))

(define (db:no-sync-del! db var)
  (sqlite3:execute db "DELETE FROM no_sync_metadat WHERE var=?;" var))

562
563
564
565
566
567
568
569

570
571
572
573
574
575
576
577
578

579
580
581








582
583

584
585
586
587
588
589
590
591
592
593

594
595

596
597
598
599
600
601

602
603
604

605
606
607
608
609
610
611
570
571
572
573
574
575
576

577
578
579
580
581
582
583
584
585

586
587


588
589
590
591
592
593
594
595
596

597
598
599
600
601
602
603
604
605
606

607
608

609
610
611
612
613
614

615
616
617

618
619
620
621
622
623
624
625







-
+








-
+

-
-
+
+
+
+
+
+
+
+

-
+









-
+

-
+





-
+


-
+







	  dbfile:lazy-modification-time 
	  file-list))))

;; dot-locking egg seems not to work, using this for now
;; if lock is older than expire-time then remove it and try again
;; to get the lock
;;
(define (common:simple-file-lock fname #!key (expire-time 300))
(define (dbfile:simple-file-lock fname #!key (expire-time 300))
  (let ((fmod-time (handle-exceptions
		       ext
		     (current-seconds)
		     (file-modification-time fname))))
    (if (file-exists? fname)
	(if (> (- (current-seconds) fmod-time) expire-time)
	    (begin
	      (handle-exceptions exn #f (delete-file* fname))	
	      (common:simple-file-lock fname expire-time: expire-time))
	      (dbfile:simple-file-lock fname expire-time: expire-time))
	    #f)
	(let ((key-string (conc (get-host-name) "-" (current-process-id))))
	  (with-output-to-file fname
	(let ((key-string (conc (get-host-name) "-" (current-process-id)))
	      (oup        (open-output-file fname)))
	  (with-output-to-port
	      oup
	    (lambda ()
	      (print key-string)))
	  (close-output-port oup)
	  #;(with-output-to-file fname
	    (lambda ()
	      (print key-string)))
	  (print key-string)))
	  (thread-sleep! 0.25)
	  (if (file-exists? fname)
	      (handle-exceptions exn
                #f 
                (with-input-from-file fname
	  	  (lambda ()
		    (equal? key-string (read-line)))))
	      #f)))))

(define (common:simple-file-lock-and-wait fname #!key (expire-time 300))
(define (dbfile:simple-file-lock-and-wait fname #!key (expire-time 300))
  (let ((end-time (+ expire-time (current-seconds))))
    (let loop ((got-lock (common:simple-file-lock fname expire-time: expire-time)))
    (let loop ((got-lock (dbfile:simple-file-lock fname expire-time: expire-time)))
      (if got-lock
	  #t
	  (if (> end-time (current-seconds))
	      (begin
		(thread-sleep! 3)
		(loop (common:simple-file-lock fname expire-time: expire-time)))
		(loop (dbfile:simple-file-lock fname expire-time: expire-time)))
	      #f)))))

(define (common:simple-file-release-lock fname)
(define (dbfile:simple-file-release-lock fname)
  (handle-exceptions
      exn
      #f ;; I don't really care why this failed (at least for now)
    (delete-file* fname)))


)