Megatest

Diff
Login

Differences From Artifact [0a05f35135]:

To Artifact [3585e1244b]:


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
44
45
46
47


48
49
50
51
52
53


54
55
56

57
58
59

60
61
62
63
64
65
66
67
68
69
70
71
72

73
74
75
76

77
78
79
80
81
82


83
84
85
86
87
88

89
90
91
92

93
94



95
96
97

98
99
100
101
102
103

104
105
106



107
108
109
110
111


112
113
114

115
116
117

118
119
120
121
122
123


124
125

126
127
128
129
130
131
132


133
134
135



136
137
138
139
140






141
142
143



144
145
146
147
148
149
150
151
152
153
154


155
156
157
158
159


160
161
162
163
164
165
166




167
168
169

170
171
172
173
174
175
176
177
178
179
180





181
182
183
184
185
186
187
188
189
190
191
192



193
194
195
196
197


198
199


200
201
202
203
204
205
206
207
208
209
210
211
212


213
214
215


216
217
218
219
220
221


222
223
224

225
226

227
228
229


230
231
232
233
234
235
236




237
238
239
240
241
242
243
244
245


246
247
248
249
250
251
252
253
254
255
256





257
258
259
260
261
262
263







264
265
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
292
293

294
295
296


297
298
299
300
301
302
303


304
305
306
307
308


309
310
311
312
313
314
315


316
317


318
319

320
321
322
323
324
325
326
327



328
329
330
331
332


333
334
335
336
337

338
339
340



341
342


343
344
345
346
347

348
349
350
351
352



353
354
355
356
357
358
359
360
361
362
363
364
365
366



367
368
369
370

371
372
373
374
375
376
377
378
379
380
381
382
383
384



385
386
387
388
389
390
391
392
393
394
395


396
397
398
399

400
401
402
403
404




405
406

407
408
409
410
411



412
413
414
415

416
417
418
419
420
421



422
423
424
425
426


427
428
429



430
431

432
433
434
435
436


437
438

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

503
504
505
506
507
508
509
510
511
512

513
514

515
516
517
518


519
520
521


522
523
524
525

526
527
528
529

530
531
532

533
534
535

536
537
538



539
540
541
542
543



544
545
546



547
548
549
550
551
552

553
554
555
556
557


558
559

560
561
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
612
613
614
615
616
617
618


619
620

621
622
623
624
625
626


627
628

629
630
631
632


633
634

635
636
637
638


639
640

641
642
643
644


645
646
647




648
649
650


651
652

653
654
655
656


657
658

659
660
661
662
663
664
665
666
667
668


669
670

671
672
673
674


675
676

677
678
679


680
681

682
683
684

685
686
687

688
689
690
691
692

693
694
695

696
697
698
699

700
701

702
703
704
705
706
707
708

709
710
711

712
713
714

715
716
717

718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743

744
745

746
747
748

749
750

751
752

753
754
755
756


757
758

759
760
761
762


763
764
765

766
767
768
769


770
771

772
773
774
775


776
777

778
779
780
781

782
783
784
785
786
787
788

789
790
791
792
793
794
795
796
797
798
799
800

801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820






821
822
823
824

825
826
827
828
829
830
831
832
833
834

835
836
837



838
839
840
841
842
843
844
845
846
847
848









849
850

851
852
853
854
855


856
857
858
859

860
861
862
863


864
865
866



867
868

869
870
871

872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898

899
900
901
902
903
904






905
906
907



908
909

910
911
912
913
914
915




916
917
918



919
920

921
922
923
924





925
926

927
928
929
930





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






44




45


46
47
48



49






50



51
52
53





54
55



56



57






58
59


60







61
62



63
64
65





66
67
68
69
70
71



72
73
74











75
76





77
78







79
80
81
82



83











84
85
86
87
88












89
90
91





92
93


94
95













96
97



98
99






100
101



102


103



104
105







106
107
108
109









110
111











112
113
114
115
116







117
118
119
120
121
122
123



124
125
126



























127



128
129







130
131





132
133







134
135


136
137


138








139
140
141





142
143





144



145
146
147


148
149





150





151
152
153














154
155
156




157














158
159
160











161
162




163





164
165
166
167


168





169
170
171




172






173
174
175





176
177



178
179
180


181





182
183


184









185




186



187
188


189


190



191




192




193




194
195


196





197
198


199




200






201





202





203










204


205




206
207



208
209




210




211



212



213



214
215
216





217
218
219



220
221
222






223





224
225


226





227
228



229


230
231



232
233
234


235







236
237










238
239




240












241











242
243


244






245
246


247




248
249


250




251
252


253




254
255



256
257
258
259



260
261


262




263
264


265










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


292




293
294



295




296
297


298




299
300


301




302







303












304




















305
306
307
308
309
310




311










312



313
314
315











316
317
318
319
320
321
322
323
324


325





326
327




328




329
330



331
332
333


334



335



























336






337
338
339
340
341
342



343
344
345


346






347
348
349
350



351
352
353


354




355
356
357
358
359


360




361
362
363
364
365







+
-
+


-
-
-
-
+
-
-
-

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

-
+

-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
-
-
-
-
-
-
+
+
-
-
-
-
-
-
+
-
-
-
-
+
-
-
+
+
+
-
-
-
+
-
-
-
-
-
-
+
-
-
-
+
+
+
-
-
-
-
-
+
+
-
-
-
+
-
-
-
+
-
-
-
-
-
-
+
+
-
-
+
-
-
-
-
-
-
-
+
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
+
+
-
-
-
-
-
-
-
+
+
+
+
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
+
+
-
-
-
-
-
-
+
+
-
-
-
+
-
-
+
-
-
-
+
+
-
-
-
-
-
-
-
+
+
+
+
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
+
+
-
-
-
-
-
-
-
+
+
-
-
-
-
-
+
+
-
-
-
-
-
-
-
+
+
-
-
+
+
-
-
+
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
-
-
-
-
-
+
-
-
-
+
+
+
-
-
+
+
-
-
-
-
-
+
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
+
-
-
-
-
-
+
+
+
+
-
-
+
-
-
-
-
-
+
+
+
-
-
-
-
+
-
-
-
-
-
-
+
+
+
-
-
-
-
-
+
+
-
-
-
+
+
+
-
-
+
-
-
-
-
-
+
+
-
-
+
-
-
-
-
-
-
-
-
-
+
-
-
-
-
+
-
-
-
+
+
-
-
+
-
-
+
-
-
-
+
-
-
-
-
+
-
-
-
-
+
-
-
-
-
+
+
-
-
+
-
-
-
-
-
+
+
-
-
+
-
-
-
-
+
-
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
-
-
+
-
-
-
-
+
+
-
-
-
+
+
-
-
-
-
+
-
-
-
-
+
-
-
-
+
-
-
-
+
-
-
-
+
+
+
-
-
-
-
-
+
+
+
-
-
-
+
+
+
-
-
-
-
-
-
+
-
-
-
-
-
+
+
-
-
+
-
-
-
-
-
+
+
-
-
-
+
-
-
+
+
-
-
-
+
+
+
-
-
+
-
-
-
-
-
-
-
+
+
-
-
-
-
-
-
-
-
-
-
+
+
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
-
-
-
-
-
-
+
+
-
-
+
-
-
-
-
+
+
-
-
+
-
-
-
-
+
+
-
-
+
-
-
-
-
+
+
-
-
-
+
+
+
+
-
-
-
+
+
-
-
+
-
-
-
-
+
+
-
-
+
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
-
-
-
-
+
+
-
-
+
-
-
-
+
+
-
-
+
-
-
-
+
-
-
-
+
-
-
-
-
-
+
-
-
-
+
-
-
-
-
+
-
-
+
-
-
-
-
-
-
-
+
-
-
-
+
-
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
+
-
-
-
+
-
-
+
-
-
+
-
-
-
-
+
+
-
-
+
-
-
-
-
+
+
-
-
-
+
-
-
-
-
+
+
-
-
+
-
-
-
-
+
+
-
-
+
-
-
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
+
-
-
-
+
+
+
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
-
-
+
-
-
-
-
-
+
+
-
-
-
-
+
-
-
-
-
+
+
-
-
-
+
+
+
-
-
+
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
+
+
+
-
-
+
-
-
-
-
-
-
+
+
+
+
-
-
-
+
+
+
-
-
+
-
-
-
-
+
+
+
+
+
-
-
+
-
-
-
-
+
+
+
+
+
;;
;;======================================================================

(use format typed-records) ;; RADT => purpose of json format??

(declare (unit rmt))
(declare (uses api))
(import api)
(declare (uses http-transport))

(include "common_records.scm")

;;
;; THESE ARE ALL CALLED ON THE CLIENT SIDE!!!
;;

(use (prefix pkts pkts:) srfi-18)
;; generate entries for ~/.megatestrc with the following
;;
;;  grep define ../rmt.scm | grep rmt: |perl -pi -e 's/\(define\s+\((\S+)\W.*$/\1/'|sort -u

;;======================================================================
;;  S U P P O R T   F U N C T I O N S
;;======================================================================

(defstruct cmdrec
;; if a server is either running or in the process of starting call client:setup
;; else return #f to let the calling proc know that there is no server available
;;
(define (rmt:get-connection-info areapath #!key (area-dat #f)) ;; TODO: push areapath down.
  (let* ((runremote (or area-dat *runremote*))
	 (cinfo     (if (remote? runremote)
			(remote-conndat runremote)
			#f)))
  cmd
  (host    #f)
	  (if cinfo
	      cinfo
	      (if (server:check-if-running areapath)
		  (client:setup areapath)
		  #f))))

  (run-ids #f)
  params)
(define *send-receive-mutex* (make-mutex)) ;; should have separate mutex per run-id

;; RA => e.g. usage (rmt:send-receive 'get-var #f (list varname))
;; call cmd on remote host (#f for any host)
;;
(define (rmt:send-receive cmd rid params #!key (attemptnum 1)(area-dat #f)) ;; start attemptnum at 1 so the modulo below works as expected

;; example: (rmt:run 'get-runs target run-name test-patt state status)
  ;;DOT digraph megatest_state_status {
  ;;DOT   ranksep=0;
  ;;DOT   // rankdir=LR;
  ;;DOT   node [shape="box"];
  ;;DOT "rmt:send-receive" -> MUTEXLOCK;
  ;;DOT { edge [style=invis];"case 1" -> "case 2" -> "case 3" -> "case 4" -> "case 5" -> "case 6" -> "case 7" -> "case 8" -> "case 9" -> "case 10" -> "case 11"; }
  ;; do all the prep locked under the rmt-mutex
  (mutex-lock! *rmt-mutex*)
  
  ;; 1. check if server is started IFF cmd is a write OR if we are not on the homehost, store in runremote
  ;; 2. check the age of the connections. refresh the connection if it is older than timeout-20 seconds.
  ;; 3. do the query, if on homehost use local access
  ;;
;;
  (let* ((start-time    (current-seconds)) ;; snapshot time so all use cases get same value
         (areapath      *toppath*);; TODO - resolve from dbstruct to be compatible with multiple areas
	 (runremote     (or area-dat
			    *runremote*))
(define (rmt:run cmd . params)
	 (readonly-mode (if (and runremote
				 (remote-ro-mode-checked runremote))
			    (remote-ro-mode runremote)
			    (let* ((dbfile  (conc *toppath* "/megatest.db"))
				   (ro-mode (not (file-write-access? dbfile)))) ;; TODO: use dbstruct or runremote to figure this out in future
			      (if runremote
  (let ((server (rmt:get-server cmdrec))) ;; look up server 
    #f))
				  (begin
				    (remote-ro-mode-set! runremote ro-mode)
				    (remote-ro-mode-checked-set! runremote #t)
				    ro-mode)
				  ro-mode)))))

  
    ;; DOT INIT_RUNREMOTE; // leaving off - doesn't really add to the clarity
    ;; DOT MUTEXLOCK -> INIT_RUNREMOTE [label="no remote?"];
    ;; DOT INIT_RUNREMOTE -> MUTEXLOCK;
    ;; ensure we have a record for our connection for given area
(define (rmt:get-connection-info . args)
    (if (not runremote)                   ;; can remove this one. should never get here.         
	(begin
  #t
  (print "Got here: rmt:get-connection-info"))
(define (rmt:send-receive . args)
	  (set! *runremote* (make-remote))
	  (set! runremote   *runremote*))) ;; new runremote will come from this on next iteration
    
  #t
    ;; DOT SET_HOMEHOST; // leaving off - doesn't really add to the clarity
    ;; DOT MUTEXLOCK -> SET_HOMEHOST [label="no homehost?"];
    ;; DOT SET_HOMEHOST -> MUTEXLOCK;
    ;; ensure we have a homehost record
    (if (not (pair? (remote-hh-dat runremote)))  ;; not on homehost
	(thread-sleep! 0.1) ;; since we shouldn't get here, delay a little
  (print "Got here: rmt:send-receive"))
	(remote-hh-dat-set! runremote (common:get-homehost)))
    
    ;;(print "BB> readonly-mode is "readonly-mode" dbfile is "dbfile)
(define (rmt:print-db-stats . args)
  #t
  (print "Got here: rmt:print-db-stats"))
    (cond
     ;;DOT EXIT;
     ;;DOT MUTEXLOCK -> EXIT [label="> 15 attempts"]; {rank=same "case 1" "EXIT" }
     ;; give up if more than 15 attempts
     ((> attemptnum 15)
(define (rmt:get-max-query-average . args)
  #t
      (debug:print 0 *default-log-port* "ERROR: 15 tries to start/connect to server. Giving up.")
      (exit 1))

  (print "Got here: rmt:get-max-query-average"))
     ;;DOT CASE2 [label="local\nreadonly\nquery"];
     ;;DOT MUTEXLOCK -> CASE2; {rank=same "case 2" CASE2}
     ;;DOT CASE2 -> "rmt:open-qry-close-locally";
(define (rmt:open-qry-close-locally . args)
     ;; readonly mode, read request-  handle it - case 2
     ((and readonly-mode
           (member cmd api:read-only-queries)) 
      (mutex-unlock! *rmt-mutex*)
      (debug:print-info 12 *default-log-port* "rmt:send-receive, case 2")
      (rmt:open-qry-close-locally cmd 0 params)
  #t
  (print "Got here: rmt:open-qry-close-locally"))
      )

(define (rmt:send-receive-no-auto-client-setup . args)
     ;;DOT CASE3 [label="write in\nread-only mode"];
     ;;DOT MUTEXLOCK -> CASE3 [label="readonly\nmode?"]; {rank=same "case 3" CASE3}
     ;;DOT CASE3 -> "#f";
     ;; readonly mode, write request.  Do nothing, return #f
     (readonly-mode
      (mutex-unlock! *rmt-mutex*)
      (debug:print-info 12 *default-log-port* "rmt:send-receive, case 3")
  #t
  (print "Got here: rmt:send-receive-no-auto-client-setup"))
      (debug:print 0 *default-log-port* "WARNING: write transaction requested on a readonly area.  cmd="cmd" params="params)
      #f)

(define (rmt:kill-server . args)
  #t
  (print "Got here: rmt:kill-server"))
     ;; This block was for pre-emptively resetting the connection if there had been no communication for some time.
     ;; I don't think it adds any value. If the server is not there, just fail and start a new connection.
     ;; also, the expire-time calculation might not be correct. We want, time-since-last-server-access > (server:get-timeout)
     ;;
     ;;DOT CASE4 [label="reset\nconnection"];
(define (rmt:start-server . args)
  #t
  (print "Got here: rmt:start-server"))
(define (rmt:login . args)
  #t
  (print "Got here: rmt:login"))
     ;;DOT MUTEXLOCK -> CASE4 [label="have connection,\nlast_access > expire_time"]; {rank=same "case 4" CASE4}
     ;;DOT CASE4 -> "rmt:send-receive";
     ;; reset the connection if it has been unused too long
(define (rmt:login-no-auto-client-setup . args)
  #t
  (print "Got here: rmt:login-no-auto-client-setup"))
     ((and runremote
           (remote-conndat runremote)
	   (> (current-seconds) ;; if it has been more than server-timeout seconds since last contact, close this connection and start a new on
	      (+ (http-transport:server-dat-get-last-access (remote-conndat runremote))
		 (remote-server-timeout runremote))))
      (debug:print-info 0 *default-log-port* "Connection to " (remote-server-url runremote) " expired due to no accesses, forcing new connection.")
      (http-transport:close-connections area-dat: runremote)
      (remote-conndat-set! runremote #f) ;; invalidate the connection, thus forcing a new connection.
      (mutex-unlock! *rmt-mutex*)
      (rmt:send-receive cmd rid params attemptnum: attemptnum))
     
(define (rmt:general-call . args)
  #t
     ;;DOT CASE5 [label="local\nread"];
     ;;DOT MUTEXLOCK -> CASE5 [label="server not required,\non homehost,\nread-only query"]; {rank=same "case 5" CASE5};
     ;;DOT CASE5 -> "rmt:open-qry-close-locally";

     ;; on homehost and this is a read
  (print "Got here: rmt:general-call"))
(define (rmt:get-latest-host-load . args)
     ((and (not (remote-force-server runremote)) ;; honor forced use of server, i.e. server NOT required
	   (cdr (remote-hh-dat runremote))       ;; on homehost
           (member cmd api:read-only-queries))   ;; this is a read
      (mutex-unlock! *rmt-mutex*)
      (debug:print-info 12 *default-log-port* "rmt:send-receive, case  5")
      (rmt:open-qry-close-locally cmd 0 params))

  #t
  (print "Got here: rmt:get-latest-host-load"))
(define (rmt:sdb-qry . args)
  #t
     ;;DOT CASE6 [label="init\nremote"];
     ;;DOT MUTEXLOCK -> CASE6 [label="on homehost,\nwrite query,\nhave server,\ncan't reach it"]; {rank=same "case 6" CASE6};
     ;;DOT CASE6 -> "rmt:send-receive";
  (print "Got here: rmt:sdb-qry"))
     ;; on homehost and this is a write, we already have a server, but server has died
     ((and (cdr (remote-hh-dat runremote))           ;; on homehost
           (not (member cmd api:read-only-queries))  ;; this is a write
           (remote-server-url runremote)             ;; have a server
           (not (server:ping (remote-server-url runremote))))  ;; server has died. NOTE: this is not a cheap call! Need better approach.
      (set! *runremote* (make-remote))
      (remote-force-server-set! runremote (common:force-server?))
      (mutex-unlock! *rmt-mutex*)
      (debug:print-info 12 *default-log-port* "rmt:send-receive, case  6")
      (rmt:send-receive cmd rid params attemptnum: attemptnum))

(define (rmt:runtests . args)
  #t
  (print "Got here: rmt:runtests"))
(define (rmt:get-run-record-ids . args)
  #t
     ;;DOT CASE7 [label="homehost\nwrite"];
     ;;DOT MUTEXLOCK -> CASE7 [label="server not required,\non homehost,\na write,\nhave a server"]; {rank=same "case 7" CASE7};
     ;;DOT CASE7 -> "rmt:open-qry-close-locally";
     ;; on homehost and this is a write, we already have a server
     ((and (not (remote-force-server runremote))     ;; honor forced use of server, i.e. server NOT required
	   (cdr (remote-hh-dat runremote))           ;; on homehost
           (not (member cmd api:read-only-queries))  ;; this is a write
           (remote-server-url runremote))            ;; have a server
      (mutex-unlock! *rmt-mutex*)
      (debug:print-info 12 *default-log-port* "rmt:send-receive, case  4.1")
      (rmt:open-qry-close-locally cmd 0 params))

  (print "Got here: rmt:get-run-record-ids"))
(define (rmt:get-changed-record-ids . args)
  #t
     ;;DOT CASE8 [label="force\nserver"];
     ;;DOT MUTEXLOCK -> CASE8 [label="server not required,\nhave homehost info,\nno connection yet,\nnot a read-only query"]; {rank=same "case 8" CASE8};
     ;;DOT CASE8 -> "rmt:open-qry-close-locally";
     ;;  on homehost, no server contact made and this is a write, passively start a server 
     ((and (not (remote-force-server runremote))     ;; honor forced use of server, i.e. server NOT required
  (print "Got here: rmt:get-changed-record-ids"))
(define (rmt:get-tests-tags . args)
	   (cdr (remote-hh-dat runremote))           ;; have homehost
           (not (remote-server-url runremote))       ;; no connection yet
  #t
  (print "Got here: rmt:get-tests-tags"))
	   (not (member cmd api:read-only-queries))) ;; not a read-only query
      (debug:print-info 12 *default-log-port* "rmt:send-receive, case  8")
      (let ((server-url  (server:check-if-running *toppath*))) ;; (server:read-dotserver->url *toppath*))) ;; (server:check-if-running *toppath*))) ;; Do NOT want to run server:check-if-running - very expensive to do for every write call
	(if server-url
	    (remote-server-url-set! runremote server-url) ;; the string can be consumed by the client setup if needed
	    (if (common:force-server?)
		(server:start-and-wait *toppath*)
		(server:kind-run *toppath*))))
      (remote-force-server-set! runremote (common:force-server?))
      (mutex-unlock! *rmt-mutex*)
      (debug:print-info 12 *default-log-port* "rmt:send-receive, case  8.1")
      (rmt:open-qry-close-locally cmd 0 params))

(define (rmt:get-key-val-pairs . args)
  #t
     ;;DOT CASE9 [label="force server\nnot on homehost"];
     ;;DOT MUTEXLOCK -> CASE9 [label="no connection\nand either require server\nor not on homehost"]; {rank=same "case 9" CASE9};
     ;;DOT CASE9 -> "start\nserver" -> "rmt:send-receive";
  (print "Got here: rmt:get-key-val-pairs"))
(define (rmt:get-keys . args)
     ((or (and (remote-force-server runremote)              ;; we are forcing a server and don't yet have a connection to one
	       (not (remote-conndat runremote)))
	  (and (not (cdr (remote-hh-dat runremote)))        ;; not on a homehost 
	       (not (remote-conndat runremote))))           ;; and no connection
      (debug:print-info 12 *default-log-port* "rmt:send-receive, case 9, hh-dat: " (remote-hh-dat runremote) " conndat: " (remote-conndat runremote))
      (mutex-unlock! *rmt-mutex*)
  #t
  (print "Got here: rmt:get-keys"))
      (if (not (server:check-if-running *toppath*)) ;; who knows, maybe one has started up?
	  (server:start-and-wait *toppath*))
      (remote-conndat-set! runremote (rmt:get-connection-info *toppath*)) ;; calls client:setup which calls client:setup-http
(define (rmt:get-keys-write . args)
      (rmt:send-receive cmd rid params attemptnum: attemptnum)) ;; TODO: add back-off timeout as

  #t
     ;;DOT CASE10 [label="on homehost"];
     ;;DOT MUTEXLOCK -> CASE10 [label="server not required,\non homehost"]; {rank=same "case 10" CASE10};
     ;;DOT CASE10 -> "rmt:open-qry-close-locally";
  (print "Got here: rmt:get-keys-write"))
(define (rmt:get-key-vals . args)
     ;; all set up if get this far, dispatch the query
     ((and (not (remote-force-server runremote))
	   (cdr (remote-hh-dat runremote))) ;; we are on homehost
      (mutex-unlock! *rmt-mutex*)
      (debug:print-info 12 *default-log-port* "rmt:send-receive, case 10")
      (rmt:open-qry-close-locally cmd (if rid rid 0) params))

  #t
  (print "Got here: rmt:get-key-vals"))
(define (rmt:get-targets . args)
  #t
     ;;DOT CASE11 [label="send_receive"];
     ;;DOT MUTEXLOCK -> CASE11 [label="else"]; {rank=same "case 11" CASE11};
     ;;DOT CASE11 -> "rmt:send-receive" [label="call failed"];
     ;;DOT CASE11 -> "RESULT" [label="call succeeded"];
     ;; not on homehost, do server query
     (else
      ;; (mutex-unlock! *rmt-mutex*)
      (debug:print-info 12 *default-log-port* "rmt:send-receive, case  9")
      ;; (mutex-lock! *rmt-mutex*)
  (print "Got here: rmt:get-targets"))
(define (rmt:get-target . args)
      (let* ((conninfo (remote-conndat runremote))
	     (dat      (case (remote-transport runremote)
			 ((http) (condition-case ;; handling here has caused a lot of problems. However it is needed to deal with attemtped communication to servers that have gone away
                                  (http-transport:client-api-send-receive 0 conninfo cmd params)
                                  ((commfail)(vector #f "communications fail"))
                                  ((exn)(vector #f "other fail" (print-call-chain)))))
			 (else
			  (debug:print 0 *default-log-port* "ERROR: transport " (remote-transport runremote) " not supported")
			  (exit))))
	     (success  (if (vector? dat) (vector-ref dat 0) #f))
	     (res      (if (vector? dat) (vector-ref dat 1) #f)))
  #t
  (print "Got here: rmt:get-target"))
(define (rmt:get-run-times . args)
  #t
  (print "Got here: rmt:get-run-times"))
	(if (and (vector? conninfo) (< 5 (vector-length conninfo)))
            (http-transport:server-dat-update-last-access conninfo) ;; refresh access time
	    (begin
              (debug:print 0 *default-log-port* "INFO: Should not get here! conninfo=" conninfo)
              (set! conninfo #f)
              (remote-conndat-set! *runremote* #f)
              (http-transport:close-connections  area-dat: runremote)))
(define (rmt:register-test . args)
  #t
  (print "Got here: rmt:register-test"))
(define (rmt:get-test-id . args)
  #t
  (print "Got here: rmt:get-test-id"))
(define (rmt:get-test-info-by-id . args)
	;; (mutex-unlock! *rmt-mutex*)
        (debug:print-info 13 *default-log-port* "rmt:send-receive, case  9. conninfo=" conninfo " dat=" dat " runremote = " runremote)
	(mutex-unlock! *rmt-mutex*)
  #t
  (print "Got here: rmt:get-test-info-by-id"))
(define (rmt:test-get-rundir-from-test-id . args)
	(if success ;; success only tells us that the transport was successful, have to examine the data to see if there was a detected issue at the other end
	    (if (and (vector? res)
		     (eq? (vector-length res) 2)
		     (eq? (vector-ref res 1) 'overloaded)) ;; since we are looking at the data to carry the error we'll use a fairly obtuse combo to minimise the chances of some sort of collision.
                ;; this is the case where the returned data is bad or the server is overloaded and we want
                ;; to ease off the queries
		(let ((wait-delay (+ attemptnum (* attemptnum 10))))
		  (debug:print 0 *default-log-port* "WARNING: server is overloaded. Delaying " wait-delay " seconds and trying call again.")
		  (mutex-lock! *rmt-mutex*)
		  (http-transport:close-connections area-dat: runremote)
		  (set! *runremote* #f) ;; force starting over
		  (mutex-unlock! *rmt-mutex*)
		  (thread-sleep! wait-delay)
		  (rmt:send-receive cmd rid params attemptnum: (+ attemptnum 1)))
		res) ;; All good, return res
	    (begin
	      (debug:print 0 *default-log-port* "WARNING: communication failed. Trying again, try num: " attemptnum)
	      (mutex-lock! *rmt-mutex*)
              (remote-conndat-set!    runremote #f)
	      (http-transport:close-connections area-dat: runremote)
	      (remote-server-url-set! runremote #f)
	      (mutex-unlock! *rmt-mutex*)
              (debug:print-info 12 *default-log-port* "rmt:send-receive, case  9.1")
	      ;; (if (not (server:check-if-running *toppath*))
	      ;; 	  (server:start-and-wait *toppath*))
	      (rmt:send-receive cmd rid params attemptnum: (+ attemptnum 1)))))))))

  #t
    ;;DOT }
    
;; (define (rmt:update-db-stats run-id rawcmd params duration)
  (print "Got here: rmt:test-get-rundir-from-test-id"))
(define (rmt:open-test-db-by-test-id . args)
;;   (mutex-lock! *db-stats-mutex*)
;;   (handle-exceptions
;;    exn
;;    (begin
;;      (debug:print 0 *default-log-port* "WARNING: stats collection failed in update-db-stats")
;;      (debug:print 0 *default-log-port* " message: " ((condition-property-accessor 'exn 'message) exn))
;;      (print "exn=" (condition->list exn))
  #t
  (print "Got here: rmt:open-test-db-by-test-id"))
;;      #f) ;; if this fails we don't care, it is just stats
;;    (let* ((cmd      (conc "run-id=" run-id " " (if (eq? rawcmd 'general-call) (car params) rawcmd)))
;; 	  (stat-vec (hash-table-ref/default *db-stats* cmd #f)))
;;      (if (not (vector? stat-vec))
;; 	 (let ((newvec (vector 0 0)))
(define (rmt:test-set-state-status-by-id . args)
  #t
;; 	   (hash-table-set! *db-stats* cmd newvec)
;; 	   (set! stat-vec newvec)))
;;      (vector-set! stat-vec 0 (+ (vector-ref stat-vec 0) 1))
;;      (vector-set! stat-vec 1 (+ (vector-ref stat-vec 1) duration))))
;;   (mutex-unlock! *db-stats-mutex*))

(define (rmt:print-db-stats)
  (print "Got here: rmt:test-set-state-status-by-id"))
(define (rmt:set-tests-state-status . args)
  (let ((fmtstr "~40a~7-d~9-d~20,2-f")) ;; "~20,2-f"
    (debug:print 18 *default-log-port* "DB Stats\n========")
  #t
  (print "Got here: rmt:set-tests-state-status"))
    (debug:print 18 *default-log-port* (format #f "~40a~8a~10a~10a" "Cmd" "Count" "TotTime" "Avg"))
    (for-each (lambda (cmd)
(define (rmt:get-tests-for-run . args)
		(let ((cmd-dat (hash-table-ref *db-stats* cmd)))
		  (debug:print 18 *default-log-port* (format #f fmtstr cmd (vector-ref cmd-dat 0) (vector-ref cmd-dat 1) (/ (vector-ref cmd-dat 1)(vector-ref cmd-dat 0))))))
	      (sort (hash-table-keys *db-stats*)
		    (lambda (a b)
		      (> (vector-ref (hash-table-ref *db-stats* a) 0)
			 (vector-ref (hash-table-ref *db-stats* b) 0)))))))

(define (rmt:get-max-query-average run-id)
  #t
  (print "Got here: rmt:get-tests-for-run"))
(define (rmt:synchash-get . args)
  (mutex-lock! *db-stats-mutex*)
  (let* ((runkey (conc "run-id=" run-id " "))
	 (cmds   (filter (lambda (x)
			   (substring-index runkey x))
			 (hash-table-keys *db-stats*)))
  #t
  (print "Got here: rmt:synchash-get"))
	 (res    (if (null? cmds)
		     (cons 'none 0)
		     (let loop ((cmd (car cmds))
				(tal (cdr cmds))
				(max-cmd (car cmds))
(define (rmt:get-tests-for-run-mindata . args)
				(res 0))
		       (let* ((cmd-dat (hash-table-ref *db-stats* cmd))
			      (tot     (vector-ref cmd-dat 0))
  #t
  (print "Got here: rmt:get-tests-for-run-mindata"))
(define (rmt:get-tests-for-runs-mindata . args)
			      (curravg (/ (vector-ref cmd-dat 1) (vector-ref cmd-dat 0))) ;; count is never zero by construction
			      (currmax (max res curravg))
  #t
  (print "Got here: rmt:get-tests-for-runs-mindata"))
			      (newmax-cmd (if (> curravg res) cmd max-cmd)))
			 (if (null? tal)
			     (if (> tot 10)
				 (cons newmax-cmd currmax)
				 (cons 'none 0))
(define (rmt:delete-test-records . args)
			     (loop (car tal)(cdr tal) newmax-cmd currmax)))))))
    (mutex-unlock! *db-stats-mutex*)
    res))

(define (rmt:open-qry-close-locally cmd run-id params #!key (remretries 5))
  #t
  (print "Got here: rmt:delete-test-records"))
(define (rmt:test-set-state-status . args)
  (let* ((qry-is-write   (not (member cmd api:read-only-queries)))
	 (db-file-path   (db:dbfile-path)) ;;  0))
	 (dbstruct-local (db:setup #t))  ;; make-dbr:dbstruct path:  dbdir local: #t)))
	 (read-only      (not (file-write-access? db-file-path)))
	 (start          (current-milliseconds))
	 (resdat         (if (not (and read-only qry-is-write))
			     (let ((v (api:execute-requests dbstruct-local (vector (symbol->string cmd) params))))
			       (handle-exceptions ;; there has been a long history of receiving strange errors from values returned by the client when things go wrong..
				exn               ;;  This is an attempt to detect that situation and recover gracefully
				(begin
				  (debug:print0 *default-log-port* "ERROR: bad data from server " v " message: "  ((condition-property-accessor 'exn 'message) exn))
				  (vector #t '())) ;; should always get a vector but if something goes wrong return a dummy
				(if (and (vector? v)
					 (> (vector-length v) 1))
  #t
  (print "Got here: rmt:test-set-state-status"))
(define (rmt:test-toplevel-num-items . args)
				    (let ((newvec (vector (vector-ref v 0)(vector-ref v 1))))
				      newvec)           ;; by copying the vector while inside the error handler we should force the detection of a corrupted record
				    (vector #t '()))))  ;; we could also check that the returned types are valid
			     (vector #t '())))
  #t
	 (success        (vector-ref resdat 0))
	 (res            (vector-ref resdat 1))
	 (duration       (- (current-milliseconds) start)))
    (if (and read-only qry-is-write)
        (debug:print 0 *default-log-port* "ERROR: attempt to write to read-only database ignored. cmd=" cmd))
    (if (not success)
	(if (> remretries 0)
	    (begin
	      (debug:print-error 0 *default-log-port* "local query failed. Trying again.")
	      (thread-sleep! (/ (random 5000) 1000)) ;; some random delay 
	      (rmt:open-qry-close-locally cmd run-id params remretries: (- remretries 1)))
	    (begin
	      (debug:print-error 0 *default-log-port* "too many retries in rmt:open-qry-close-locally, giving up")
	      #f))
  (print "Got here: rmt:test-toplevel-num-items"))
(define (rmt:get-matching-previous-test-run-records . args)
  #t
	(begin
	  ;; (rmt:update-db-stats run-id cmd params duration)
	  ;; mark this run as dirty if this was a write, the watchdog is responsible for syncing it
	  (if qry-is-write
	      (let ((start-time (current-seconds)))
		(mutex-lock! *db-multi-sync-mutex*)
/		(set! *db-last-access* start-time)  ;; THIS IS PROBABLY USELESS? (we are on a client)
                (mutex-unlock! *db-multi-sync-mutex*)))))
    res))

(define (rmt:send-receive-no-auto-client-setup connection-info cmd run-id params)
  (print "Got here: rmt:get-matching-previous-test-run-records"))
(define (rmt:test-get-logfile-info . args)
  (let* ((run-id   (if run-id run-id 0))
	 (res  	   (handle-exceptions
		    exn
		    #f
  #t
		    (http-transport:client-api-send-receive run-id connection-info cmd params))))
    (if (and res (vector-ref res 0))
	(vector-ref res 1) ;;; YES!! THIS IS CORRECT!! CHANGE IT HERE, THEN CHANGE rmt:send-receive ALSO!!!
	#f)))

  (print "Got here: rmt:test-get-logfile-info"))
(define (rmt:test-get-records-for-index-file . args)
  #t
  (print "Got here: rmt:test-get-records-for-index-file"))
;; ;; Wrap json library for strings (why the ports crap in the first place?)
;; (define (rmt:dat->json-str dat)
(define (rmt:get-testinfo-state-status . args)
;;   (with-output-to-string 
;;     (lambda ()
;;       (json-write dat))))
;; 
;; (define (rmt:json-str->dat json-str)
  #t
  (print "Got here: rmt:get-testinfo-state-status"))
(define (rmt:test-set-log! . args)
;;   (with-input-from-string json-str
;;     (lambda ()
;;       (json-read))))

  #t
;;======================================================================
;;
;; A C T U A L   A P I   C A L L S  
;;
;;======================================================================

  (print "Got here: rmt:test-set-log!"))
(define (rmt:test-set-top-process-pid . args)
  #t
;;======================================================================
;;  S E R V E R
;;======================================================================

(define (rmt:kill-server run-id)
  (print "Got here: rmt:test-set-top-process-pid"))
(define (rmt:test-get-top-process-pid . args)
  (rmt:send-receive 'kill-server run-id (list run-id)))

(define (rmt:start-server run-id)
  #t
  (print "Got here: rmt:test-get-top-process-pid"))
(define (rmt:get-run-ids-matching-target . args)
  (rmt:send-receive 'start-server 0 (list run-id)))

  #t
;;======================================================================
;;  M I S C
;;======================================================================

(define (rmt:login run-id)
  (print "Got here: rmt:get-run-ids-matching-target"))
(define (rmt:test-get-paths-matching-keynames-target-new . args)
  (rmt:send-receive 'login run-id (list *toppath* megatest-version *my-client-signature*)))

  #t
;; This login does no retries under the hood - it acts a bit like a ping.
;; Deprecated for nmsg-transport.
;;
(define (rmt:login-no-auto-client-setup connection-info)
  (case *transport-type* ;; run-id of 0 is just a placeholder
    ((http)(rmt:send-receive-no-auto-client-setup connection-info 'login 0 (list *toppath* megatest-version *my-client-signature*)))
    ;;((nmsg)(nmsg-transport:client-api-send-receive run-id connection-info 'login (list *toppath* megatest-version run-id *my-client-signature*)))
    ))

  (print "Got here: rmt:test-get-paths-matching-keynames-target-new"))
;; hand off a call to one of the db:queries statements
;; added run-id to make looking up the correct db possible 
;;
(define (rmt:general-call stmtname run-id . params)
(define (rmt:get-prereqs-not-met . args)
  (rmt:send-receive 'general-call run-id (append (list stmtname run-id) params)))


  #t
  (print "Got here: rmt:get-prereqs-not-met"))
;; given a hostname, return a pair of cpu load and update time representing latest intelligence from tests running on that host
(define (rmt:get-latest-host-load hostname)
(define (rmt:get-count-tests-running-for-run-id . args)
  (rmt:send-receive 'get-latest-host-load 0 (list hostname)))

  #t
;; (define (rmt:sync-inmem->db run-id)
;;   (rmt:send-receive 'sync-inmem->db run-id '()))

  (print "Got here: rmt:get-count-tests-running-for-run-id"))
(define (rmt:sdb-qry qry val run-id)
  ;; add caching if qry is 'getid or 'getstr
  (rmt:send-receive 'sdb-qry run-id (list qry val)))

(define (rmt:get-count-tests-running . args)
;; NOT COMPLETED
(define (rmt:runtests user run-id testpatt params)
  (rmt:send-receive 'runtests run-id testpatt))

  #t
(define (rmt:get-run-record-ids  target run keynames test-patt)
  (rmt:send-receive 'get-run-record-ids #f (list target run keynames test-patt)))

(define (rmt:get-changed-record-ids since-time)
  (print "Got here: rmt:get-count-tests-running"))
(define (rmt:get-count-tests-running-for-testname . args)
  (rmt:send-receive 'get-changed-record-ids #f (list since-time)) )

  #t
;;======================================================================
;;  T E S T   M E T A 
;;======================================================================

(define (rmt:get-tests-tags)
  (print "Got here: rmt:get-count-tests-running-for-testname"))
(define (rmt:get-count-tests-running-in-jobgroup . args)
  (rmt:send-receive 'get-tests-tags #f '()))

  #t
;;======================================================================
;;  K E Y S 
;;======================================================================

  (print "Got here: rmt:get-count-tests-running-in-jobgroup"))
;; These require run-id because the values come from the run!
;;
(define (rmt:get-key-val-pairs run-id)
  (rmt:send-receive 'get-key-val-pairs run-id (list run-id)))

(define (rmt:get-keys)
(define (rmt:set-state-status-and-roll-up-items . args)
  (if *db-keys* *db-keys* 
     (let ((res (rmt:send-receive 'get-keys #f '())))
       (set! *db-keys* res)
       res)))

  #t
(define (rmt:get-keys-write) ;; dummy query to force server start
  (let ((res (rmt:send-receive 'get-keys-write #f '())))
    (set! *db-keys* res)
    res))

  (print "Got here: rmt:set-state-status-and-roll-up-items"))
;; we don't reuse run-id's (except possibly *after* a db cleanup) so it is safe
;; to cache the resuls in a hash
;;
(define (rmt:get-key-vals run-id)
  (or (hash-table-ref/default *keyvals* run-id #f)
      (let ((res (rmt:send-receive 'get-key-vals #f (list run-id))))
        (hash-table-set! *keyvals* run-id res)
        res)))

(define (rmt:get-targets)
(define (rmt:update-pass-fail-counts . args)
  (rmt:send-receive 'get-targets #f '()))

  #t
(define (rmt:get-target run-id)
  (rmt:send-receive 'get-target run-id (list run-id)))

(define (rmt:get-run-times runpatt targetpatt)
  (print "Got here: rmt:update-pass-fail-counts"))
(define (rmt:top-test-set-per-pf-counts . args)
  (rmt:send-receive 'get-run-times #f (list runpatt targetpatt ))) 


  #t
  (print "Got here: rmt:top-test-set-per-pf-counts"))
;;======================================================================
;;  T E S T S
;;======================================================================

(define (rmt:get-raw-run-stats . args)
;; Just some syntatic sugar
(define (rmt:register-test run-id test-name item-path)
  (rmt:general-call 'register-test run-id run-id test-name item-path))

  #t
(define (rmt:get-test-id run-id testname item-path)
  (rmt:send-receive 'get-test-id run-id (list run-id testname item-path)))

  (print "Got here: rmt:get-raw-run-stats"))
;; run-id is NOT used
;;
(define (rmt:get-test-info-by-id run-id test-id)
(define (rmt:get-test-times . args)
  (if (number? test-id)
      (rmt:send-receive 'get-test-info-by-id run-id (list run-id test-id))
      (begin
  #t
  (print "Got here: rmt:get-test-times"))
(define (rmt:get-run-info . args)
	(debug:print 0 *default-log-port* "WARNING: Bad data handed to rmt:get-test-info-by-id run-id=" run-id ", test-id=" test-id)
	(print-call-chain (current-error-port))
	#f)))

(define (rmt:test-get-rundir-from-test-id run-id test-id)
  #t
  (print "Got here: rmt:get-run-info"))
(define (rmt:get-num-runs . args)
  (rmt:send-receive 'test-get-rundir-from-test-id run-id (list run-id test-id)))

(define (rmt:open-test-db-by-test-id run-id test-id #!key (work-area #f))
  #t
  (print "Got here: rmt:get-num-runs"))
(define (rmt:get-runs-cnt-by-patt . args)
  (let* ((test-path (if (string? work-area)
			work-area
			(rmt:test-get-rundir-from-test-id run-id test-id))))
    (debug:print 3 *default-log-port* "TEST PATH: " test-path)
    (open-test-db test-path)))

  #t
;; WARNING: This currently bypasses the transaction wrapped writes system
(define (rmt:test-set-state-status-by-id run-id test-id newstate newstatus newcomment)
  (rmt:send-receive 'test-set-state-status-by-id run-id (list run-id test-id newstate newstatus newcomment)))

(define (rmt:set-tests-state-status run-id                      testnames currstate currstatus newstate newstatus)
  (print "Got here: rmt:get-runs-cnt-by-patt"))
(define (rmt:register-run . args)
  (rmt:send-receive 'set-tests-state-status run-id (list run-id testnames currstate currstatus newstate newstatus)))

  #t
(define (rmt:get-tests-for-run run-id testpatt states statuses offset limit not-in sort-by sort-order qryvals last-update mode)
  ;; (if (number? run-id)
  (rmt:send-receive 'get-tests-for-run run-id (list run-id testpatt states statuses offset limit not-in sort-by sort-order qryvals last-update mode)))
  ;;    (begin
  ;;	(debug:print-error 0 *default-log-port* "rmt:get-tests-for-run called with bad run-id=" run-id)
  (print "Got here: rmt:register-run"))
(define (rmt:get-run-name-from-id . args)
  ;;	(print-call-chain (current-error-port))
  ;;	'())))

  #t
;; get stuff via synchash 
(define (rmt:synchash-get run-id proc synckey keynum params)
  (print "Got here: rmt:get-run-name-from-id"))
(define (rmt:delete-run . args)
  (rmt:send-receive 'synchash-get run-id (list run-id proc synckey keynum params)))

(define (rmt:get-tests-for-run-mindata run-id testpatt states status not-in)
  #t
  (print "Got here: rmt:delete-run"))
(define (rmt:update-run-stats . args)
  (rmt:send-receive 'get-tests-for-run-mindata run-id (list run-id testpatt states status not-in)))
  
  #t
;; IDEA: Threadify these - they spend a lot of time waiting ...
;;
(define (rmt:get-tests-for-runs-mindata run-ids testpatt states status not-in)
  (let ((multi-run-mutex (make-mutex))
	(run-id-list (if run-ids
			 run-ids
			 (rmt:get-all-run-ids)))
  (print "Got here: rmt:update-run-stats"))
(define (rmt:delete-old-deleted-test-records . args)
	(result      '()))
    (if (null? run-id-list)
	'()
	(let loop ((hed     (car run-id-list))
		   (tal     (cdr run-id-list))
		   (threads '()))
	  (if (> (length threads) 5)
	      (loop hed tal (filter (lambda (th)(not (member (thread-state th) '(terminated dead)))) threads))
	      (let* ((newthread (make-thread
				 (lambda ()
  #t
  (print "Got here: rmt:delete-old-deleted-test-records"))
				   (let ((res (rmt:send-receive 'get-tests-for-run-mindata hed (list hed testpatt states status not-in))))
				     (if (list? res)
					 (begin
					   (mutex-lock! multi-run-mutex)
(define (rmt:get-runs . args)
					   (set! result (append result res))
					   (mutex-unlock! multi-run-mutex))
					 (debug:print-error 0 *default-log-port* "get-tests-for-run-mindata failed for run-id " hed ", testpatt " testpatt ", states " states ", status " status ", not-in " not-in))))
				 (conc "multi-run-thread for run-id " hed)))
		     (newthreads (cons newthread threads)))
		(thread-start! newthread)
		(thread-sleep! 0.05) ;; give that thread some time to start
		(if (null? tal)
		    newthreads
		    (loop (car tal)(cdr tal) newthreads))))))
    result))

  #t
;; ;; IDEA: Threadify these - they spend a lot of time waiting ...
;; ;;
;; (define (rmt:get-tests-for-runs-mindata run-ids testpatt states status not-in)
;;   (let ((run-id-list (if run-ids
;; 			 run-ids
;; 			 (rmt:get-all-run-ids))))
;;     (apply append (map (lambda (run-id)
;; 			 (rmt:send-receive 'get-tests-for-run-mindata run-id (list run-ids testpatt states status not-in)))
;; 		       run-id-list))))

(define (rmt:delete-test-records run-id test-id)
  (print "Got here: rmt:get-runs"))
(define (rmt:simple-get-runs . args)
  (rmt:send-receive 'delete-test-records run-id (list run-id test-id)))

  #t
;; This is not needed as test steps are deleted on test delete call
;;
;; (define (rmt:delete-test-step-records run-id test-id)
;;   (rmt:send-receive 'delete-test-step-records run-id (list run-id test-id)))

(define (rmt:test-set-state-status run-id test-id state status msg)
  (print "Got here: rmt:simple-get-runs"))
(define (rmt:get-all-run-ids . args)
  (rmt:send-receive 'test-set-state-status run-id (list run-id test-id state status msg)))

  #t
(define (rmt:test-toplevel-num-items run-id test-name)
  (rmt:send-receive 'test-toplevel-num-items run-id (list run-id test-name)))

;; (define (rmt:get-previous-test-run-record run-id test-name item-path)
  (print "Got here: rmt:get-all-run-ids"))
(define (rmt:get-prev-run-ids . args)
;;   (rmt:send-receive 'get-previous-test-run-record run-id (list run-id test-name item-path)))

  #t
(define (rmt:get-matching-previous-test-run-records run-id test-name item-path)
  (rmt:send-receive 'get-matching-previous-test-run-records run-id (list run-id test-name item-path)))

(define (rmt:test-get-logfile-info run-id test-name)
  (print "Got here: rmt:get-prev-run-ids"))
(define (rmt:lock/unlock-run . args)
  (rmt:send-receive 'test-get-logfile-info run-id (list run-id test-name)))

  #t
(define (rmt:test-get-records-for-index-file run-id test-name)
  (rmt:send-receive 'test-get-records-for-index-file run-id (list run-id test-name)))

(define (rmt:get-testinfo-state-status run-id test-id)
  (print "Got here: rmt:lock/unlock-run"))
(define (rmt:get-run-status . args)
  (rmt:send-receive 'get-testinfo-state-status run-id (list run-id test-id)))

(define (rmt:test-set-log! run-id test-id logf)
  #t
  (print "Got here: rmt:get-run-status"))
(define (rmt:set-run-status . args)
  #t
  (if (string? logf)(rmt:general-call 'test-set-log run-id logf test-id)))

(define (rmt:test-set-top-process-pid run-id test-id pid)
  (print "Got here: rmt:set-run-status"))
(define (rmt:update-run-event_time . args)
  (rmt:send-receive 'test-set-top-process-pid run-id (list run-id test-id pid)))

  #t
(define (rmt:test-get-top-process-pid run-id test-id)
  (rmt:send-receive 'test-get-top-process-pid run-id (list run-id test-id)))

(define (rmt:get-run-ids-matching-target keynames target res runname testpatt statepatt statuspatt)
  (print "Got here: rmt:update-run-event_time"))
(define (rmt:get-runs-by-patt . args)
  (rmt:send-receive 'get-run-ids-matching-target #f (list keynames target res runname testpatt statepatt statuspatt)))

  #t
;; NOTE: This will open and access ALL run databases. 
;;
(define (rmt:test-get-paths-matching-keynames-target-new keynames target res testpatt statepatt statuspatt runname)
  (let ((run-ids (rmt:get-run-ids-matching-target keynames target res runname testpatt statepatt statuspatt)))
    (apply append 
	   (map (lambda (run-id)
		  (rmt:send-receive 'test-get-paths-matching-keynames-target-new run-id (list run-id keynames target res testpatt statepatt statuspatt runname)))
	   run-ids))))

;; (define (rmt:get-run-ids-matching keynames target res)
  (print "Got here: rmt:get-runs-by-patt"))
(define (rmt:find-and-mark-incomplete . args)
;;   (rmt:send-receive #f 'get-run-ids-matching (list keynames target res)))

  #t
(define (rmt:get-prereqs-not-met run-id waitons ref-test-name ref-item-path #!key (mode '(normal))(itemmaps #f))
  (rmt:send-receive 'get-prereqs-not-met run-id (list run-id waitons ref-test-name ref-item-path mode itemmaps)))

(define (rmt:get-count-tests-running-for-run-id run-id)
  (print "Got here: rmt:find-and-mark-incomplete"))
(define (rmt:get-main-run-stats . args)
  (rmt:send-receive 'get-count-tests-running-for-run-id run-id (list run-id)))

  #t
;; Statistical queries

(define (rmt:get-count-tests-running run-id)
  (print "Got here: rmt:get-main-run-stats"))
(define (rmt:get-var . args)
  (rmt:send-receive 'get-count-tests-running run-id (list run-id)))

  #t
(define (rmt:get-count-tests-running-for-testname run-id testname)
  (rmt:send-receive 'get-count-tests-running-for-testname run-id (list run-id testname)))

  (print "Got here: rmt:get-var"))
(define (rmt:get-count-tests-running-in-jobgroup run-id jobgroup)
  (rmt:send-receive 'get-count-tests-running-in-jobgroup run-id (list run-id jobgroup)))

(define (rmt:del-var . args)
;; state and status are extra hints not usually used in the calculation
;;
(define (rmt:set-state-status-and-roll-up-items run-id test-name item-path state status comment)
  (rmt:send-receive 'set-state-status-and-roll-up-items run-id (list run-id test-name item-path state status comment)))

  #t
(define (rmt:update-pass-fail-counts run-id test-name)
  (rmt:general-call 'update-pass-fail-counts run-id test-name test-name test-name))

  (print "Got here: rmt:del-var"))
(define (rmt:top-test-set-per-pf-counts run-id test-name)
  (rmt:send-receive 'top-test-set-per-pf-counts run-id (list run-id test-name)))

(define (rmt:get-raw-run-stats run-id)
(define (rmt:set-var . args)
  (rmt:send-receive 'get-raw-run-stats run-id (list run-id)))

  #t
(define (rmt:get-test-times runname target)
  (rmt:send-receive 'get-test-times #f (list runname target ))) 

;;======================================================================
;;  R U N S
;;======================================================================

  (print "Got here: rmt:set-var"))
(define (rmt:get-run-info run-id)
  (rmt:send-receive 'get-run-info run-id (list run-id)))

(define (rmt:find-and-mark-incomplete-all-runs . args)
(define (rmt:get-num-runs runpatt)
  (rmt:send-receive 'get-num-runs #f (list runpatt)))

  #t
(define (rmt:get-runs-cnt-by-patt runpatt targetpatt keys)
  (rmt:send-receive 'get-runs-cnt-by-patt #f (list runpatt  targetpatt keys)))

  (print "Got here: rmt:find-and-mark-incomplete-all-runs"))
;; Use the special run-id == #f scenario here since there is no run yet
(define (rmt:register-run keyvals runname state status user contour)
  (rmt:send-receive 'register-run #f (list keyvals runname state status user contour)))
    
(define (rmt:get-run-name-from-id run-id)
  (rmt:send-receive 'get-run-name-from-id run-id (list run-id)))

(define (rmt:delete-run run-id)
  (rmt:send-receive 'delete-run run-id (list run-id)))

(define (rmt:update-run-stats run-id stats)
  (rmt:send-receive 'update-run-stats #f (list run-id stats)))

(define (rmt:delete-old-deleted-test-records)
  (rmt:send-receive 'delete-old-deleted-test-records #f '()))

(define (rmt:get-runs runpatt count offset keypatts)
  (rmt:send-receive 'get-runs #f (list runpatt count offset keypatts)))

(define (rmt:simple-get-runs runpatt count offset target)
  (rmt:send-receive 'simple-get-runs #f (list runpatt count offset target)))

(define (rmt:get-all-run-ids)
  (rmt:send-receive 'get-all-run-ids #f '()))

(define (rmt:get-prev-run-ids run-id)
(define (rmt:get-previous-test-run-record . args)
  (rmt:send-receive 'get-prev-run-ids #f (list run-id)))

  #t
(define (rmt:lock/unlock-run run-id lock unlock user)
  (rmt:send-receive 'lock/unlock-run #f (list run-id lock unlock user)))

  (print "Got here: rmt:get-previous-test-run-record"))
;; set/get status
(define (rmt:get-run-status run-id)
(define (rmt:get-run-stats . args)
  (rmt:send-receive 'get-run-status #f (list run-id)))

  #t
(define (rmt:set-run-status run-id run-status #!key (msg #f))
  (rmt:send-receive 'set-run-status #f (list run-id run-status msg)))

(define (rmt:update-run-event_time run-id)
  (print "Got here: rmt:get-run-stats"))
(define (rmt:teststep-set-status! . args)
  (rmt:send-receive 'update-run-event_time #f (list run-id)))

  #t
(define (rmt:get-runs-by-patt  keys runnamepatt targpatt offset limit fields last-runs-update  #!key  (sort-order "asc")) ;; fields of #f uses default
  (rmt:send-receive 'get-runs-by-patt #f (list keys runnamepatt targpatt offset limit fields last-runs-update sort-order)))

(define (rmt:find-and-mark-incomplete run-id ovr-deadtime)
  (print "Got here: rmt:teststep-set-status!"))
(define (rmt:get-steps-for-test . args)
  ;; (if (rmt:send-receive 'have-incompletes? run-id (list run-id ovr-deadtime))
  (rmt:send-receive 'mark-incomplete run-id (list run-id ovr-deadtime))) ;; )

  #t
(define (rmt:get-main-run-stats run-id)
  (rmt:send-receive 'get-main-run-stats #f (list run-id)))

(define (rmt:get-var varname)
  (print "Got here: rmt:get-steps-for-test"))
(define (rmt:get-steps-info-by-id . args)
  (rmt:send-receive 'get-var #f (list varname)))

  #t
(define (rmt:del-var varname)
  (rmt:send-receive 'del-var #f (list varname)))

(define (rmt:set-var varname value)
  (print "Got here: rmt:get-steps-info-by-id"))
(define (rmt:read-test-data . args)
  (rmt:send-receive 'set-var #f (list varname value)))

  #t
;;======================================================================
;; M U L T I R U N   Q U E R I E S
;;======================================================================

  (print "Got here: rmt:read-test-data"))
;; Need to move this to multi-run section and make associated changes
(define (rmt:find-and-mark-incomplete-all-runs #!key (ovr-deadtime #f))
  (let ((run-ids (rmt:get-all-run-ids)))
    (for-each (lambda (run-id)
	       (rmt:find-and-mark-incomplete run-id ovr-deadtime))
	     run-ids)))

(define (rmt:read-test-data* . args)
;; get the previous record for when this test was run where all keys match but runname
;; returns #f if no such test found, returns a single test record if found
;; 
;; Run this at the client end since we have to connect to multiple run-id dbs
;;
(define (rmt:get-previous-test-run-record run-id test-name item-path)
  (let* ((keyvals (rmt:get-key-val-pairs run-id))
	 (keys    (rmt:get-keys))
	 (selstr  (string-intersperse  keys ","))
	 (qrystr  (string-intersperse (map (lambda (x)(conc x "=?")) keys) " AND ")))
    (if (not keyvals)
	#f
  #t
	(let ((prev-run-ids (rmt:get-prev-run-ids run-id)))
	  ;; for each run starting with the most recent look to see if there is a matching test
	  ;; if found then return that matching test record
	  (debug:print 4 *default-log-port* "selstr: " selstr ", qrystr: " qrystr ", keyvals: " keyvals ", previous run ids found: " prev-run-ids)
	  (if (null? prev-run-ids) #f
	      (let loop ((hed (car prev-run-ids))
			 (tal (cdr prev-run-ids)))
		(let ((results (rmt:get-tests-for-run hed (conc test-name "/" item-path) '() '() ;; run-id testpatt states statuses
						      #f #f #f               ;; offset limit not-in hide/not-hide
						      #f #f #f #f 'normal))) ;; sort-by sort-order qryvals last-update mode
		  (debug:print 4 *default-log-port* "Got tests for run-id " run-id ", test-name " test-name ", item-path " item-path ": " results)
		  (if (and (null? results)
			   (not (null? tal)))
		      (loop (car tal)(cdr tal))
		      (if (null? results) #f
			  (car results))))))))))

(define (rmt:get-run-stats)
  (rmt:send-receive 'get-run-stats #f '()))

  (print "Got here: rmt:read-test-data*"))
(define (rmt:get-data-info-by-id . args)
  #t
  (print "Got here: rmt:get-data-info-by-id"))
(define (rmt:testmeta-add-record . args)
  #t
;;======================================================================
;;  S T E P S
;;======================================================================

  (print "Got here: rmt:testmeta-add-record"))
;; Getting steps is more complicated.
;;
;; If given work area 
;;  1. Find the testdat.db file
;;  2. Open the testdat.db file and do the query
;; If not given the work area
;;  1. Do a remote call to get the test path
;;  2. Continue as above
;; 
;;(define (rmt:get-steps-for-test run-id test-id)
(define (rmt:testmeta-get-record . args)
;;  (rmt:send-receive 'get-steps-data run-id (list test-id)))

(define (rmt:teststep-set-status! run-id test-id teststep-name state-in status-in comment logfile)
  #t
  (print "Got here: rmt:testmeta-get-record"))
(define (rmt:testmeta-update-field . args)
  (let* ((state     (items:check-valid-items "state" state-in))
	 (status    (items:check-valid-items "status" status-in)))
    (if (or (not state)(not status))
	(debug:print 3 *default-log-port* "WARNING: Invalid " (if status "status" "state")
		     " value \"" (if status state-in status-in) "\", update your validvalues section in megatest.config"))
    (rmt:send-receive 'teststep-set-status! run-id (list run-id test-id teststep-name state-in status-in comment logfile))))

(define (rmt:get-steps-for-test run-id test-id)
  (rmt:send-receive 'get-steps-for-test run-id (list run-id test-id)))

(define (rmt:get-steps-info-by-id test-step-id)
  #t
  (print "Got here: rmt:testmeta-update-field"))
(define (rmt:test-data-rollup . args)
  #t
  (print "Got here: rmt:test-data-rollup"))
(define (rmt:csv->test-data . args)
  #t
  (print "Got here: rmt:csv->test-data"))
(define (rmt:tasks-find-task-queue-records . args)
  (rmt:send-receive 'get-steps-info-by-id #f (list test-step-id)))

  #t
;;======================================================================
;;  T E S T   D A T A 
;;======================================================================

(define (rmt:read-test-data run-id test-id categorypatt #!key (work-area #f)) 
  (print "Got here: rmt:tasks-find-task-queue-records"))
(define (rmt:tasks-add . args)
  (rmt:send-receive 'read-test-data run-id (list run-id test-id categorypatt)))
(define (rmt:read-test-data* run-id test-id categorypatt varpatt #!key (work-area #f)) 
  (rmt:send-receive 'read-test-data* run-id (list run-id test-id categorypatt varpatt)))

  #t
(define (rmt:get-data-info-by-id test-data-id)
   (rmt:send-receive 'get-data-info-by-id #f (list test-data-id)))

(define (rmt:testmeta-add-record testname)
  (print "Got here: rmt:tasks-add"))
(define (rmt:tasks-set-state-given-param-key . args)
  (rmt:send-receive 'testmeta-add-record #f (list testname)))

(define (rmt:testmeta-get-record testname)
  #t
  (print "Got here: rmt:tasks-set-state-given-param-key"))
(define (rmt:tasks-get-last . args)
  (rmt:send-receive 'testmeta-get-record #f (list testname)))

  #t
(define (rmt:testmeta-update-field test-name fld val)
  (rmt:send-receive 'testmeta-update-field #f (list test-name fld val)))

  (print "Got here: rmt:tasks-get-last"))
(define (rmt:test-data-rollup run-id test-id status)
  (rmt:send-receive 'test-data-rollup run-id (list run-id test-id status)))

(define (rmt:csv->test-data run-id test-id csvdata)
  (rmt:send-receive 'csv->test-data run-id (list run-id test-id csvdata)))

;;======================================================================
;;  T A S K S
;;======================================================================

(define (rmt:tasks-find-task-queue-records target run-name test-patt state-patt action-patt)
  (rmt:send-receive 'find-task-queue-records #f (list target run-name test-patt state-patt action-patt)))

(define (rmt:tasks-add action owner target runname testpatt params)
  (rmt:send-receive 'tasks-add #f (list action owner target runname testpatt params)))

(define (rmt:tasks-set-state-given-param-key param-key new-state)
  (rmt:send-receive 'tasks-set-state-given-param-key #f (list  param-key new-state)))

(define (rmt:tasks-get-last target runname)
  (rmt:send-receive 'tasks-get-last #f (list target runname)))

;;======================================================================
;; N O   S Y N C   D B 
;;======================================================================

(define (rmt:no-sync-set var val)
(define (rmt:no-sync-set . args)
  (rmt:send-receive 'no-sync-set #f `(,var ,val)))

(define (rmt:no-sync-get/default var default)
  (rmt:send-receive 'no-sync-get/default #f `(,var ,default)))

(define (rmt:no-sync-del! var)
  #t
  (print "Got here: rmt:no-sync-set"))
(define (rmt:no-sync-get/default . args)
  #t
  (print "Got here: rmt:no-sync-get/default"))
(define (rmt:no-sync-del! . args)
  (rmt:send-receive 'no-sync-del! #f `(,var)))

(define (rmt:no-sync-get-lock keyname)
  #t
  (print "Got here: rmt:no-sync-del!"))
(define (rmt:no-sync-get-lock . args)
  (rmt:send-receive 'no-sync-get-lock #f `(,keyname)))

  #t
;;======================================================================
;; A R C H I V E S
;;======================================================================

(define (rmt:archive-get-allocations  testname itempath dneeded)
  (rmt:send-receive 'archive-get-allocations #f (list testname itempath dneeded)))
  (print "Got here: rmt:no-sync-get-lock"))
(define (rmt:archive-get-allocations . args)
  #t
  (print "Got here: rmt:archive-get-allocations"))

(define (rmt:archive-register-block-name bdisk-id archive-path)
  (rmt:send-receive 'archive-register-block-name #f (list bdisk-id archive-path)))
(define (rmt:archive-register-block-name . args)
  #t
  (print "Got here: rmt:archive-register-block-name"))

(define (rmt:archive-allocate-testsuite/area-to-block block-id testsuite-name areakey)
(define (rmt:archive-allocate-testsuite/area-to-block . args)
  (rmt:send-receive 'archive-allocate-test-to-block #f (list  block-id testsuite-name areakey)))

(define (rmt:archive-register-disk bdisk-name bdisk-path df)
  (rmt:send-receive 'archive-register-disk #f (list bdisk-name bdisk-path df)))
  #t
  (print "Got here: rmt:archive-allocate-testsuite/area-to-block"))
(define (rmt:archive-register-disk . args)
  #t
  (print "Got here: rmt:archive-register-disk"))

(define (rmt:test-set-archive-block-id run-id test-id archive-block-id)
(define (rmt:test-set-archive-block-id . args)
  (rmt:send-receive 'test-set-archive-block-id run-id (list run-id test-id archive-block-id)))

(define (rmt:test-get-archive-block-info archive-block-id)
  (rmt:send-receive 'test-get-archive-block-info #f (list archive-block-id)))
  #t
  (print "Got here: rmt:test-set-archive-block-id"))
(define (rmt:test-get-archive-block-info . args)
  #t
  (print "Got here: rmt:test-get-archive-block-info"))