1 // This file is part of BOINC.
2 // http://boinc.berkeley.edu
3 // Copyright (C) 2008 University of California
4 //
5 // BOINC is free software; you can redistribute it and/or modify it
6 // under the terms of the GNU Lesser General Public License
7 // as published by the Free Software Foundation,
8 // either version 3 of the License, or (at your option) any later version.
9 //
10 // BOINC is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 // See the GNU Lesser General Public License for more details.
14 //
15 // You should have received a copy of the GNU Lesser General Public License
16 // along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
17 
18 #include "config.h"
19 #include <cstdlib>
20 #include <string>
21 #include <cstring>
22 #include <ctime>
23 #include <unistd.h>
24 #include <cmath>
25 
26 // For machines with finite() defined in ieeefp.h
27 #if HAVE_IEEEFP_H
28 #include <ieeefp.h>
29 #endif
30 
31 #include "common_defs.h"
32 #include "str_util.h"
33 #include "str_replace.h"
34 #include "util.h"
35 #include "error_numbers.h"
36 #include "boinc_db.h"
37 
38 #ifdef _USING_FCGI_
39 #include "fcgi_stdio.h"
40 #endif
41 
42 using std::string;
43 
44 extern "C" {
45     int isnan(double);
46 }
47 
48 DB_CONN boinc_db;
49 
50 static struct random_init {
random_initrandom_init51     random_init() {
52         srand48(getpid() + time(0));
53     }
54 } random_init;
55 
56 #define ESCAPE(x) escape_string(x, sizeof(x))
57 #define UNESCAPE(x) unescape_string(x, sizeof(x))
58 
59 #define strcpy2(x, y) \
60     { \
61         const char* z = y; \
62         if (!z) { \
63             x[0]=0; \
64         } else { \
65             strlcpy(x, z, sizeof(x)); \
66         } \
67     }
68 
69 
clear()70 void PLATFORM::clear() {memset(this, 0, sizeof(*this));}
clear()71 void APP::clear() {memset(this, 0, sizeof(*this));}
clear()72 void APP_VERSION::clear() {memset(this, 0, sizeof(*this));}
clear()73 void USER::clear() {memset(this, 0, sizeof(*this));}
clear()74 void TEAM::clear() {memset(this, 0, sizeof(*this));}
clear()75 void HOST::clear() {memset(this, 0, sizeof(*this));}
clear()76 void RESULT::clear() {
77     memset(this, 0, sizeof(*this));
78     size_class = -1;
79 }
clear()80 void WORKUNIT::clear() {
81     memset(this, 0, sizeof(*this));
82     size_class = -1;
83 }
clear()84 void CREDITED_JOB::clear() {memset(this, 0, sizeof(*this));}
clear()85 void MSG_FROM_HOST::clear() {memset(this, 0, sizeof(*this));}
clear()86 void MSG_TO_HOST::clear() {memset(this, 0, sizeof(*this));}
clear()87 void ASSIGNMENT::clear() {memset(this, 0, sizeof(*this));}
clear()88 void TRANSITIONER_ITEM::clear() {memset(this, 0, sizeof(*this));}
clear()89 void VALIDATOR_ITEM::clear() {memset(this, 0, sizeof(*this));}
clear()90 void SCHED_RESULT_ITEM::clear() {memset(this, 0, sizeof(*this));}
clear()91 void HOST_APP_VERSION::clear() {memset(this, 0, sizeof(*this));}
clear()92 void USER_SUBMIT::clear() {memset(this, 0, sizeof(*this));}
clear()93 void STATE_COUNTS::clear() {memset(this, 0, sizeof(*this));}
clear()94 void FILE_ITEM::clear() {memset(this, 0, sizeof(*this));}
clear()95 void FILESET_ITEM::clear() {memset(this, 0, sizeof(*this));}
clear()96 void FILESET_FILE_ITEM::clear() {memset(this, 0, sizeof(*this));}
clear()97 void SCHED_TRIGGER_ITEM::clear() {
98     id = 0;
99     fileset_id = 0;
100     need_work = false;
101     work_available = false;
102     no_work_available = false;
103     working_set_removal = false;
104 }
clear()105 void FILESET_SCHED_TRIGGER_ITEM::clear() {memset(this, 0, sizeof(*this));}
clear()106 void VDA_FILE::clear() {memset(this, 0, sizeof(*this));}
clear()107 void VDA_CHUNK_HOST::clear() {memset(this, 0, sizeof(*this));}
clear()108 void BADGE::clear() {memset(this, 0, sizeof(*this));}
clear()109 void BADGE_USER::clear() {memset(this, 0, sizeof(*this));}
clear()110 void BADGE_TEAM::clear() {memset(this, 0, sizeof(*this));}
clear()111 void CREDIT_USER::clear() {memset(this, 0, sizeof(*this));}
clear()112 void CREDIT_TEAM::clear() {memset(this, 0, sizeof(*this));}
113 
DB_PLATFORM(DB_CONN * dc)114 DB_PLATFORM::DB_PLATFORM(DB_CONN* dc) :
115     DB_BASE("platform", dc?dc:&boinc_db){}
DB_APP(DB_CONN * dc)116 DB_APP::DB_APP(DB_CONN* dc) :
117     DB_BASE("app", dc?dc:&boinc_db){}
DB_APP_VERSION(DB_CONN * dc)118 DB_APP_VERSION::DB_APP_VERSION(DB_CONN* dc) :
119     DB_BASE("app_version", dc?dc:&boinc_db){}
DB_USER(DB_CONN * dc)120 DB_USER::DB_USER(DB_CONN* dc) :
121     DB_BASE("user", dc?dc:&boinc_db){}
DB_TEAM(DB_CONN * dc)122 DB_TEAM::DB_TEAM(DB_CONN* dc) :
123     DB_BASE("team", dc?dc:&boinc_db){}
DB_HOST(DB_CONN * dc)124 DB_HOST::DB_HOST(DB_CONN* dc) :
125     DB_BASE("host", dc?dc:&boinc_db){}
DB_WORKUNIT(DB_CONN * dc)126 DB_WORKUNIT::DB_WORKUNIT(DB_CONN* dc) :
127     DB_BASE("workunit", dc?dc:&boinc_db){}
DB_CREDITED_JOB(DB_CONN * dc)128 DB_CREDITED_JOB::DB_CREDITED_JOB(DB_CONN* dc) :
129     DB_BASE("credited_job", dc?dc:&boinc_db){}
DB_RESULT(DB_CONN * dc)130 DB_RESULT::DB_RESULT(DB_CONN* dc) :
131     DB_BASE("result", dc?dc:&boinc_db), RESULT() {}
DB_MSG_FROM_HOST(DB_CONN * dc)132 DB_MSG_FROM_HOST::DB_MSG_FROM_HOST(DB_CONN* dc) :
133     DB_BASE("msg_from_host", dc?dc:&boinc_db){}
DB_MSG_TO_HOST(DB_CONN * dc)134 DB_MSG_TO_HOST::DB_MSG_TO_HOST(DB_CONN* dc) :
135     DB_BASE("msg_to_host", dc?dc:&boinc_db){}
DB_ASSIGNMENT(DB_CONN * dc)136 DB_ASSIGNMENT::DB_ASSIGNMENT(DB_CONN* dc) :
137     DB_BASE("assignment", dc?dc:&boinc_db){}
DB_HOST_APP_VERSION(DB_CONN * dc)138 DB_HOST_APP_VERSION::DB_HOST_APP_VERSION(DB_CONN* dc) :
139     DB_BASE("host_app_version", dc?dc:&boinc_db){}
DB_USER_SUBMIT(DB_CONN * dc)140 DB_USER_SUBMIT::DB_USER_SUBMIT(DB_CONN* dc) :
141     DB_BASE("user_submit", dc?dc:&boinc_db){}
DB_STATE_COUNTS(DB_CONN * dc)142 DB_STATE_COUNTS::DB_STATE_COUNTS(DB_CONN* dc) :
143     DB_BASE("state_counts", dc?dc:&boinc_db){}
DB_TRANSITIONER_ITEM_SET(DB_CONN * dc)144 DB_TRANSITIONER_ITEM_SET::DB_TRANSITIONER_ITEM_SET(DB_CONN* dc) :
145     DB_BASE_SPECIAL(dc?dc:&boinc_db){}
DB_VALIDATOR_ITEM_SET(DB_CONN * dc)146 DB_VALIDATOR_ITEM_SET::DB_VALIDATOR_ITEM_SET(DB_CONN* dc) :
147     DB_BASE_SPECIAL(dc?dc:&boinc_db){}
DB_WORK_ITEM(DB_CONN * dc)148 DB_WORK_ITEM::DB_WORK_ITEM(DB_CONN* dc) :
149     DB_BASE_SPECIAL(dc?dc:&boinc_db
150 ){
151     start_id = 0;
152 }
DB_IN_PROGRESS_RESULT(DB_CONN * dc)153 DB_IN_PROGRESS_RESULT::DB_IN_PROGRESS_RESULT(DB_CONN* dc) :
154     DB_BASE_SPECIAL(dc?dc:&boinc_db){}
DB_SCHED_RESULT_ITEM_SET(DB_CONN * dc)155 DB_SCHED_RESULT_ITEM_SET::DB_SCHED_RESULT_ITEM_SET(DB_CONN* dc) :
156     DB_BASE_SPECIAL(dc?dc:&boinc_db){}
DB_FILE(DB_CONN * dc)157 DB_FILE::DB_FILE(DB_CONN* dc) :
158     DB_BASE("file", dc?dc:&boinc_db){}
DB_FILESET(DB_CONN * dc)159 DB_FILESET::DB_FILESET(DB_CONN* dc) :
160     DB_BASE("fileset", dc?dc:&boinc_db){}
DB_FILESET_FILE(DB_CONN * dc)161 DB_FILESET_FILE::DB_FILESET_FILE(DB_CONN* dc) :
162     DB_BASE("fileset_file", dc?dc:&boinc_db){}
DB_SCHED_TRIGGER(DB_CONN * dc)163 DB_SCHED_TRIGGER::DB_SCHED_TRIGGER(DB_CONN* dc) :
164     DB_BASE("sched_trigger", dc?dc:&boinc_db) {
165     id = 0;
166     fileset_id = 0;
167     need_work = false;
168     work_available = false;
169     no_work_available = false;
170     working_set_removal = false;
171 }
DB_FILESET_SCHED_TRIGGER_ITEM(DB_CONN * dc)172 DB_FILESET_SCHED_TRIGGER_ITEM::DB_FILESET_SCHED_TRIGGER_ITEM(DB_CONN* dc) :
173     DB_BASE_SPECIAL(dc?dc:&boinc_db){}
DB_FILESET_SCHED_TRIGGER_ITEM_SET(DB_CONN * dc)174 DB_FILESET_SCHED_TRIGGER_ITEM_SET::DB_FILESET_SCHED_TRIGGER_ITEM_SET(DB_CONN* dc) :
175     DB_BASE_SPECIAL(dc?dc:&boinc_db){}
DB_VDA_FILE(DB_CONN * dc)176 DB_VDA_FILE::DB_VDA_FILE(DB_CONN* dc) :
177     DB_BASE("vda_file", dc?dc:&boinc_db){}
DB_VDA_CHUNK_HOST(DB_CONN * dc)178 DB_VDA_CHUNK_HOST::DB_VDA_CHUNK_HOST(DB_CONN* dc) :
179     DB_BASE("vda_chunk_host", dc?dc:&boinc_db){}
DB_BADGE(DB_CONN * dc)180 DB_BADGE::DB_BADGE(DB_CONN* dc) :
181     DB_BASE("badge", dc?dc:&boinc_db){}
DB_BADGE_USER(DB_CONN * dc)182 DB_BADGE_USER::DB_BADGE_USER(DB_CONN* dc) :
183     DB_BASE("badge_user", dc?dc:&boinc_db){}
DB_BADGE_TEAM(DB_CONN * dc)184 DB_BADGE_TEAM::DB_BADGE_TEAM(DB_CONN* dc) :
185     DB_BASE("badge_team", dc?dc:&boinc_db){}
DB_CREDIT_USER(DB_CONN * dc)186 DB_CREDIT_USER::DB_CREDIT_USER(DB_CONN* dc) :
187     DB_BASE("credit_user", dc?dc:&boinc_db){}
DB_CREDIT_TEAM(DB_CONN * dc)188 DB_CREDIT_TEAM::DB_CREDIT_TEAM(DB_CONN* dc) :
189     DB_BASE("credit_team", dc?dc:&boinc_db){}
190 
get_id()191 DB_ID_TYPE DB_PLATFORM::get_id() {return id;}
get_id()192 DB_ID_TYPE DB_APP::get_id() {return id;}
get_id()193 DB_ID_TYPE DB_APP_VERSION::get_id() {return id;}
get_id()194 DB_ID_TYPE DB_USER::get_id() {return id;}
get_id()195 DB_ID_TYPE DB_TEAM::get_id() {return id;}
get_id()196 DB_ID_TYPE DB_HOST::get_id() {return id;}
get_id()197 DB_ID_TYPE DB_WORKUNIT::get_id() {return id;}
get_id()198 DB_ID_TYPE DB_RESULT::get_id() {return id;}
get_id()199 DB_ID_TYPE DB_MSG_FROM_HOST::get_id() {return id;}
get_id()200 DB_ID_TYPE DB_MSG_TO_HOST::get_id() {return id;}
get_id()201 DB_ID_TYPE DB_ASSIGNMENT::get_id() {return id;}
get_id()202 DB_ID_TYPE DB_STATE_COUNTS::get_id() {return appid;}
get_id()203 DB_ID_TYPE DB_FILE::get_id() {return id;}
get_id()204 DB_ID_TYPE DB_FILESET::get_id() {return id;}
get_id()205 DB_ID_TYPE DB_SCHED_TRIGGER::get_id() {return id;}
get_id()206 DB_ID_TYPE DB_VDA_FILE::get_id() {return id;}
207 
db_print(char * buf)208 void DB_PLATFORM::db_print(char* buf){
209     sprintf(buf,
210         "create_time=%d, name='%s', user_friendly_name='%s', "
211         "deprecated=%d",
212         create_time, name, user_friendly_name,
213         deprecated
214     );
215 }
216 
db_parse(MYSQL_ROW & r)217 void DB_PLATFORM::db_parse(MYSQL_ROW &r) {
218     int i=0;
219     clear();
220     id = atol(r[i++]);
221     create_time = atoi(r[i++]);
222     strcpy2(name, r[i++]);
223     strcpy2(user_friendly_name, r[i++]);
224     deprecated = atoi(r[i++]);
225 }
226 
db_print(char * buf)227 void DB_APP::db_print(char* buf){
228     sprintf(buf,
229         "create_time=%d, "
230         "name='%s', "
231         "min_version=%d, "
232         "deprecated=%d, "
233         "user_friendly_name='%s', "
234         "homogeneous_redundancy=%d, "
235         "weight=%.15e, "
236         "beta=%d, "
237         "target_nresults=%d, "
238         "min_avg_pfc=%.15e, "
239         "host_scale_check=%d, "
240         "homogeneous_app_version=%d, "
241         "non_cpu_intensive=%d, "
242         "locality_scheduling=%d, "
243         "n_size_classes=%d, "
244         "fraction_done_exact=%d ",
245         create_time,
246         name,
247         min_version,
248         deprecated?1:0,
249         user_friendly_name,
250         homogeneous_redundancy,
251         weight,
252         beta?1:0,
253         target_nresults,
254         min_avg_pfc,
255         host_scale_check?1:0,
256         homogeneous_app_version?1:0,
257         non_cpu_intensive?1:0,
258         locality_scheduling,
259         n_size_classes,
260         fraction_done_exact?1:0
261     );
262 }
263 
db_parse(MYSQL_ROW & r)264 void DB_APP::db_parse(MYSQL_ROW &r) {
265     int i=0;
266     clear();
267     id = atol(r[i++]);
268     create_time = atoi(r[i++]);
269     strcpy2(name, r[i++]);
270     min_version = atoi(r[i++]);
271     deprecated = atoi(r[i++]);
272     strcpy2(user_friendly_name, r[i++]);
273     homogeneous_redundancy = atoi(r[i++]);
274     weight = atof(r[i++]);
275     beta = atoi(r[i++]);
276     target_nresults = atoi(r[i++]);
277     min_avg_pfc = atof(r[i++]);
278     host_scale_check = (atoi(r[i++]) != 0);
279     homogeneous_app_version = (atoi(r[i++]) != 0);
280     non_cpu_intensive = (atoi(r[i++]) != 0);
281     locality_scheduling = atoi(r[i++]);
282     n_size_classes = atoi(r[i++]);
283     fraction_done_exact = (atoi(r[i++]) != 0);
284 }
285 
db_print(char * buf)286 void DB_APP_VERSION::db_print(char* buf){
287     sprintf(buf,
288         "create_time=%d, "
289         "appid=%lu, "
290         "version_num=%d, "
291         "platformid=%lu, "
292         "xml_doc='%s', "
293         "min_core_version=%d, "
294         "max_core_version=%d, "
295         "deprecated=%d, "
296         "plan_class='%s', "
297         "pfc_n=%.15e, "
298         "pfc_avg=%.15e, "
299         "pfc_scale=%.15e, "
300         "expavg_credit=%.15e, "
301         "expavg_time=%.15e, "
302         "beta=%d ",
303         create_time,
304         appid,
305         version_num,
306         platformid,
307         xml_doc,
308         min_core_version,
309         max_core_version,
310         deprecated,
311         plan_class,
312         pfc.n,
313         pfc.avg,
314         pfc_scale,
315         expavg_credit,
316         expavg_time,
317         beta
318     );
319 }
320 
db_parse(MYSQL_ROW & r)321 void DB_APP_VERSION::db_parse(MYSQL_ROW &r) {
322     int i=0;
323     clear();
324     id = atol(r[i++]);
325     create_time = atoi(r[i++]);
326     appid = atol(r[i++]);
327     version_num = atoi(r[i++]);
328     platformid = atol(r[i++]);
329     strcpy2(xml_doc, r[i++]);
330     min_core_version = atoi(r[i++]);
331     max_core_version = atoi(r[i++]);
332     deprecated = atoi(r[i++]);
333     strcpy2(plan_class, r[i++]);
334     pfc.n = atof(r[i++]);
335     pfc.avg = atof(r[i++]);
336     pfc_scale = atof(r[i++]);
337     expavg_credit = atof(r[i++]);
338     expavg_time = atof(r[i++]);
339     beta = atoi(r[i++]);
340 }
341 
db_print(char * buf)342 void DB_USER::db_print(char* buf){
343     ESCAPE(email_addr);
344     ESCAPE(name);
345     ESCAPE(country);
346     ESCAPE(postal_code);
347     ESCAPE(global_prefs);
348     ESCAPE(project_prefs);
349     ESCAPE(url);
350     ESCAPE(signature);
351     sprintf(buf,
352         "create_time=%d, email_addr='%s', name='%s', "
353         "authenticator='%s', "
354         "country='%s', postal_code='%s', "
355         "total_credit=%.15e, expavg_credit=%.15e, expavg_time=%.15e, "
356         "global_prefs='%s', project_prefs='%s', "
357         "teamid=%lu, venue='%s', url='%s', send_email=%d, show_hosts=%d, "
358         "posts=%d, "
359         "seti_id=%d, seti_nresults=%d, seti_last_result_time=%d, "
360         "seti_total_cpu=%.15e, signature='%s', has_profile=%d, "
361         "cross_project_id='%s', passwd_hash='%s', "
362         "email_validated=%d, donated=%d",
363         create_time, email_addr, name,
364         authenticator,
365         country, postal_code,
366         total_credit, expavg_credit, expavg_time,
367         global_prefs, project_prefs,
368         teamid, venue, url, send_email, show_hosts,
369         posts,
370         seti_id, seti_nresults, seti_last_result_time,
371         seti_total_cpu, signature, has_profile,
372         cross_project_id, passwd_hash,
373         email_validated, donated
374     );
375     UNESCAPE(email_addr);
376     UNESCAPE(name);
377     UNESCAPE(country);
378     UNESCAPE(postal_code);
379     UNESCAPE(global_prefs);
380     UNESCAPE(project_prefs);
381     UNESCAPE(url);
382     UNESCAPE(signature);
383 }
384 
db_parse(MYSQL_ROW & r)385 void DB_USER::db_parse(MYSQL_ROW &r) {
386     int i=0;
387     clear();
388     id = atol(r[i++]);
389     create_time = atoi(r[i++]);
390     strcpy2(email_addr, r[i++]);
391     strcpy2(name, r[i++]);
392     strcpy2(authenticator, r[i++]);
393     strcpy2(country, r[i++]);
394     strcpy2(postal_code, r[i++]);
395     total_credit = atof(r[i++]);
396     expavg_credit = atof(r[i++]);
397     expavg_time = atof(r[i++]);
398     strcpy2(global_prefs, r[i++]);
399     strcpy2(project_prefs, r[i++]);
400     teamid = atol(r[i++]);
401     strcpy2(venue, r[i++]);
402     strcpy2(url, r[i++]);
403     send_email = atoi(r[i++]);
404     show_hosts = atoi(r[i++]);
405     posts = safe_atoi(r[i++]);
406     seti_id = safe_atoi(r[i++]);
407     seti_nresults = safe_atoi(r[i++]);
408     seti_last_result_time = safe_atoi(r[i++]);
409     seti_total_cpu = safe_atof(r[i++]);
410     strcpy2(signature, r[i++]);
411     has_profile = atoi(r[i++]);
412     strcpy2(cross_project_id, r[i++]);
413     strcpy2(passwd_hash, r[i++]);
414     email_validated = atoi(r[i++]);
415     donated = atoi(r[i++]);
416 }
417 
db_print(char * buf)418 void DB_TEAM::db_print(char* buf){
419     ESCAPE(name);
420     ESCAPE(name_lc);
421     ESCAPE(url);
422     ESCAPE(name_html);
423     ESCAPE(description);
424     sprintf(buf,
425         "create_time=%d, userid=%lu, name='%s', "
426         "name_lc='%s', url='%s', "
427         "type=%d, name_html='%s', description='%s', nusers=%d, "
428         "country='%s', "
429         "total_credit=%.15e, expavg_credit=%.15e, expavg_time=%.15e, "
430         "seti_id=%d, ping_user=%d, ping_time=%d",
431         create_time,
432         userid,
433         name,
434         name_lc,
435         url,
436         type,
437         name_html,
438         description,
439         nusers,
440         country,
441         total_credit,
442         expavg_credit,
443         expavg_time,
444         seti_id,
445         ping_user,
446         ping_time
447     );
448     UNESCAPE(name);
449     UNESCAPE(name_lc);
450     UNESCAPE(url);
451     UNESCAPE(name_html);
452     UNESCAPE(description);
453 }
454 
db_parse(MYSQL_ROW & r)455 void DB_TEAM::db_parse(MYSQL_ROW &r) {
456     int i=0;
457     clear();
458     id = atol(r[i++]);
459     create_time = atoi(r[i++]);
460     userid = atol(r[i++]);
461     strcpy2(name, r[i++]);
462     strcpy2(name_lc, r[i++]);
463     strcpy2(url, r[i++]);
464     type = atoi(r[i++]);
465     strcpy2(name_html, r[i++]);
466     strcpy2(description, r[i++]);
467     nusers = atoi(r[i++]);
468     strcpy2(country, r[i++]);
469     total_credit = atof(r[i++]);
470     expavg_credit = atof(r[i++]);
471     expavg_time = atof(r[i++]);
472     seti_id = safe_atoi(r[i++]);
473     ping_user = safe_atoi(r[i++]);
474     ping_time = safe_atoi(r[i++]);
475 }
476 
477 // set NaNs and infs to zeroes
478 //
fix_nans()479 void HOST::fix_nans() {
480     if (!finite(p_fpops)) p_fpops = 0;
481     if (!finite(p_iops)) p_iops = 0;
482     if (!finite(p_membw)) p_membw = 0;
483     if (!finite(m_nbytes)) m_nbytes = 0;
484     if (!finite(m_cache)) m_cache = 0;
485     if (!finite(m_swap)) m_swap = 0;
486     if (!finite(d_total)) d_total = 0;
487     if (!finite(d_free)) d_free = 0;
488     if (!finite(d_boinc_used_total)) d_boinc_used_total = 0;
489     if (!finite(d_boinc_used_project)) d_boinc_used_project = 0;
490     if (!finite(d_boinc_max)) d_boinc_max = 0;
491     if (!finite(n_bwup)) n_bwup = 0;
492     if (!finite(n_bwdown)) n_bwdown = 0;
493 }
494 
db_print(char * buf)495 void DB_HOST::db_print(char* buf){
496     ESCAPE(domain_name);
497     ESCAPE(serialnum);
498     ESCAPE(last_ip_addr);
499     ESCAPE(host_cpid);
500     ESCAPE(p_vendor);
501     ESCAPE(p_model);
502     ESCAPE(os_name);
503     ESCAPE(os_version);
504     ESCAPE(product_name);
505     sprintf(buf,
506         "create_time=%d, userid=%lu, "
507         "rpc_seqno=%d, rpc_time=%d, "
508         "total_credit=%.12e, expavg_credit=%.12e, expavg_time=%.15e, "
509         "timezone=%d, domain_name='%s', serialnum='%s', "
510         "last_ip_addr='%s', nsame_ip_addr=%d, "
511         "on_frac=%.15e, connected_frac=%.15e, "
512         "active_frac=%.15e, cpu_efficiency=%.15e, "
513         "duration_correction_factor=%.15e, "
514         "p_ncpus=%d, p_vendor='%s', p_model='%s', "
515         "p_fpops=%.15e, p_iops=%.15e, p_membw=%.15e, "
516         "os_name='%s', os_version='%s', "
517         "m_nbytes=%.15e, m_cache=%.15e, m_swap=%.15e, "
518         "d_total=%.15e, d_free=%.15e, "
519         "d_boinc_used_total=%.15e, d_boinc_used_project=%.15e, d_boinc_max=%.15e, "
520         "n_bwup=%.15e, n_bwdown=%.15e, "
521         "credit_per_cpu_sec=%.15e, "
522         "venue='%s', nresults_today=%d, "
523         "avg_turnaround=%.15e, "
524         "host_cpid='%s', external_ip_addr='%s', max_results_day=%d, "
525         "error_rate=%.15e, "
526         "product_name='%s', "
527         "gpu_active_frac=%.15e ",
528         create_time, userid,
529         rpc_seqno, rpc_time,
530         total_credit, expavg_credit, expavg_time,
531         timezone, domain_name, serialnum,
532         last_ip_addr, nsame_ip_addr,
533         on_frac, connected_frac,
534         active_frac, cpu_efficiency,
535         duration_correction_factor,
536         p_ncpus, p_vendor, p_model,
537         p_fpops, p_iops, p_membw,
538         os_name, os_version,
539         m_nbytes, m_cache, m_swap,
540         d_total, d_free,
541         d_boinc_used_total, d_boinc_used_project, d_boinc_max,
542         n_bwup, n_bwdown,
543         credit_per_cpu_sec,
544         venue, nresults_today,
545         avg_turnaround,
546         host_cpid, external_ip_addr, _max_results_day,
547         _error_rate,
548         product_name,
549         gpu_active_frac
550     );
551     UNESCAPE(domain_name);
552     UNESCAPE(serialnum);
553     UNESCAPE(last_ip_addr);
554     UNESCAPE(p_vendor);
555     UNESCAPE(p_model);
556     UNESCAPE(os_name);
557     UNESCAPE(os_version);
558     UNESCAPE(host_cpid);
559     UNESCAPE(product_name);
560 }
561 
db_parse(MYSQL_ROW & r)562 void DB_HOST::db_parse(MYSQL_ROW &r) {
563     int i=0;
564     clear();
565     id = atol(r[i++]);
566     create_time = atoi(r[i++]);
567     userid = atol(r[i++]);
568     rpc_seqno = atoi(r[i++]);
569     rpc_time = atoi(r[i++]);
570     total_credit = atof(r[i++]);
571     expavg_credit = atof(r[i++]);
572     expavg_time = atof(r[i++]);
573     timezone = atoi(r[i++]);
574     strcpy2(domain_name, r[i++]);
575     strcpy2(serialnum, r[i++]);
576     strcpy2(last_ip_addr, r[i++]);
577     nsame_ip_addr = atoi(r[i++]);
578     on_frac = atof(r[i++]);
579     connected_frac = atof(r[i++]);
580     active_frac = atof(r[i++]);
581     cpu_efficiency = atof(r[i++]);
582     duration_correction_factor = atof(r[i++]);
583     p_ncpus = atoi(r[i++]);
584     strcpy2(p_vendor, r[i++]);
585     strcpy2(p_model, r[i++]);
586     p_fpops = atof(r[i++]);
587     p_iops = atof(r[i++]);
588     p_membw = atof(r[i++]);
589     strcpy2(os_name, r[i++]);
590     strcpy2(os_version, r[i++]);
591     m_nbytes = atof(r[i++]);
592     m_cache = atof(r[i++]);
593     m_swap = atof(r[i++]);
594     d_total = atof(r[i++]);
595     d_free = atof(r[i++]);
596     d_boinc_used_total = atof(r[i++]);
597     d_boinc_used_project = atof(r[i++]);
598     d_boinc_max = atof(r[i++]);
599     n_bwup = atof(r[i++]);
600     n_bwdown = atof(r[i++]);
601     credit_per_cpu_sec = atof(r[i++]);
602     strcpy2(venue, r[i++]);
603     nresults_today = atoi(r[i++]);
604     avg_turnaround = atof(r[i++]);
605     strcpy2(host_cpid, r[i++]);
606     strcpy2(external_ip_addr, r[i++]);
607     _max_results_day = atoi(r[i++]);
608     _error_rate = atof(r[i++]);
609     strcpy2(product_name, r[i++]);
610     gpu_active_frac = atof(r[i++]);
611 }
612 
update_diff_validator(HOST & h)613 int DB_HOST::update_diff_validator(HOST& h) {
614     char buf[BLOB_SIZE], updates[BLOB_SIZE], query[BLOB_SIZE];
615     strcpy(updates, "");
616     if (avg_turnaround != h.avg_turnaround) {
617         sprintf(buf, " avg_turnaround=%.15e,", avg_turnaround);
618         strcat(updates, buf);
619     }
620 #if 0
621     if (error_rate != h.error_rate) {
622         sprintf(buf, " error_rate=%.15e,", error_rate);
623         strcat(updates, buf);
624     }
625 #endif
626     if (total_credit != h.total_credit) {
627         sprintf(buf, " total_credit=total_credit+%.15e,",
628             total_credit-h.total_credit
629         );
630         strcat(updates, buf);
631     }
632     if (expavg_credit != h.expavg_credit) {
633         sprintf(buf, " expavg_credit=%.15e,", expavg_credit);
634         strcat(updates, buf);
635     }
636     if (expavg_time != h.expavg_time) {
637         sprintf(buf, " expavg_time=%.15e,", expavg_time);
638         strcat(updates, buf);
639     }
640 #if 0
641     if (credit_per_cpu_sec != h.credit_per_cpu_sec) {
642         sprintf(buf, " credit_per_cpu_sec=%.15e,", credit_per_cpu_sec);
643         strcat(updates, buf);
644     }
645 #endif
646     int n = strlen(updates);
647     if (n == 0) return 0;
648     updates[n-1] = 0;        // trim the final comma
649     sprintf(query, "update host set %s where id=%lu", updates, id);
650     return db->do_query(query);
651 }
652 
653 // Update fields that differ from the argument HOST.
654 // Called from scheduler (handle_request.cpp),
655 // so only include fields modified by the scheduler.
656 //
update_diff_sched(HOST & h)657 int DB_HOST::update_diff_sched(HOST& h) {
658     char buf[BLOB_SIZE], updates[BLOB_SIZE], query[BLOB_SIZE];
659     strcpy(updates, "");
660     if (rpc_seqno != h.rpc_seqno) {
661         sprintf(buf, " rpc_seqno=%d,", rpc_seqno);
662         strcat(updates, buf);
663     }
664     if (rpc_time != h.rpc_time) {
665         sprintf(buf, " rpc_time=%d,", rpc_time);
666         strcat(updates, buf);
667     }
668     if (timezone != h.timezone) {
669         sprintf(buf, " timezone=%d,", timezone);
670         strcat(updates, buf);
671     }
672     if (strcmp(domain_name, h.domain_name)) {
673         escape_string(domain_name, sizeof(domain_name));
674         sprintf(buf, " domain_name='%s',", domain_name);
675         unescape_string(domain_name, sizeof(domain_name));
676         strcat(updates, buf);
677     }
678     if (strcmp(serialnum, h.serialnum)) {
679         escape_string(serialnum, sizeof(serialnum));
680         sprintf(buf, " serialnum='%s',", serialnum);
681         unescape_string(serialnum, sizeof(serialnum));
682         strcat(updates, buf);
683     }
684     if (strcmp(last_ip_addr, h.last_ip_addr)) {
685         escape_string(last_ip_addr, sizeof(last_ip_addr));
686         sprintf(buf, " last_ip_addr='%s',", last_ip_addr);
687         unescape_string(last_ip_addr, sizeof(last_ip_addr));
688         strcat(updates, buf);
689     }
690     if (nsame_ip_addr != h.nsame_ip_addr) {
691         sprintf(buf, " nsame_ip_addr=%d,", nsame_ip_addr);
692         strcat(updates, buf);
693     }
694     if (on_frac != h.on_frac) {
695         sprintf(buf, " on_frac=%.15e,", on_frac);
696         strcat(updates, buf);
697     }
698     if (connected_frac != h.connected_frac) {
699         sprintf(buf, " connected_frac=%.15e,", connected_frac);
700         strcat(updates, buf);
701     }
702     if (active_frac != h.active_frac) {
703         sprintf(buf, " active_frac=%.15e,", active_frac);
704         strcat(updates, buf);
705     }
706     if (cpu_efficiency != h.cpu_efficiency) {
707         sprintf(buf, " cpu_efficiency=%.15e,", cpu_efficiency);
708         strcat(updates, buf);
709     }
710     if (duration_correction_factor != h.duration_correction_factor) {
711         sprintf(buf, " duration_correction_factor=%.15e,", duration_correction_factor);
712         strcat(updates, buf);
713     }
714     if (p_ncpus != h.p_ncpus) {
715         sprintf(buf, " p_ncpus=%d,", p_ncpus);
716         strcat(updates, buf);
717     }
718     if (strcmp(p_vendor, h.p_vendor)) {
719         escape_string(p_vendor, sizeof(p_vendor));
720         sprintf(buf, " p_vendor='%s',", p_vendor);
721         unescape_string(p_vendor, sizeof(p_vendor));
722         strcat(updates, buf);
723     }
724     if (strcmp(p_model, h.p_model)) {
725         escape_string(p_model, sizeof(p_model));
726         sprintf(buf, " p_model='%s',", p_model);
727         unescape_string(p_model, sizeof(p_model));
728         strcat(updates, buf);
729     }
730     if (p_fpops != h.p_fpops) {
731         sprintf(buf, " p_fpops=%.15e,", p_fpops);
732         strcat(updates, buf);
733     }
734     if (p_iops != h.p_iops) {
735         sprintf(buf, " p_iops=%.15e,", p_iops);
736         strcat(updates, buf);
737     }
738     if (p_membw != h.p_membw) {
739         sprintf(buf, " p_membw=%.15e,", p_membw);
740         strcat(updates, buf);
741     }
742     if (strcmp(os_name, h.os_name)) {
743         escape_string(os_name, sizeof(os_name));
744         sprintf(buf, " os_name='%s',", os_name);
745         unescape_string(os_name, sizeof(os_name));
746         strcat(updates, buf);
747     }
748     if (strcmp(os_version, h.os_version)) {
749         escape_string(os_version, sizeof(os_version));
750         sprintf(buf, " os_version='%s',", os_version);
751         unescape_string(os_version, sizeof(os_version));
752         strcat(updates, buf);
753     }
754     if (m_nbytes != h.m_nbytes) {
755         sprintf(buf, " m_nbytes=%.15e,", m_nbytes);
756         strcat(updates, buf);
757     }
758     if (m_cache != h.m_cache) {
759         sprintf(buf, " m_cache=%.15e,", m_cache);
760         strcat(updates, buf);
761     }
762     if (m_swap != h.m_swap) {
763         sprintf(buf, " m_swap=%.15e,", m_swap);
764         strcat(updates, buf);
765     }
766     if (d_total != h.d_total) {
767         sprintf(buf, " d_total=%.15e,", d_total);
768         strcat(updates, buf);
769     }
770     if (d_free != h.d_free) {
771         sprintf(buf, " d_free=%.15e,", d_free);
772         strcat(updates, buf);
773     }
774     if (d_boinc_used_total != h.d_boinc_used_total) {
775         sprintf(buf, " d_boinc_used_total=%.15e,", d_boinc_used_total);
776         strcat(updates, buf);
777     }
778     if (d_boinc_used_project != h.d_boinc_used_project) {
779         sprintf(buf, " d_boinc_used_project=%.15e,", d_boinc_used_project);
780         strcat(updates, buf);
781     }
782     if (d_boinc_max != h.d_boinc_max) {
783         sprintf(buf, " d_boinc_max=%.15e,", d_boinc_max);
784         strcat(updates, buf);
785     }
786     if (n_bwdown != h.n_bwdown) {
787         sprintf(buf, " n_bwdown=%.15e,", n_bwdown);
788         strcat(updates, buf);
789     }
790     if (n_bwup != h.n_bwup) {
791         sprintf(buf, " n_bwup=%.15e,", n_bwup);
792         strcat(updates, buf);
793     }
794     if (strcmp(venue, h.venue)) {
795         escape_string(venue, sizeof(venue));
796         sprintf(buf, " venue='%s',", venue);
797         unescape_string(venue, sizeof(venue));
798         strcat(updates, buf);
799     }
800     if (nresults_today != h.nresults_today) {
801         sprintf(buf, " nresults_today=%d,", nresults_today);
802         strcat(updates, buf);
803     }
804     if (avg_turnaround != h.avg_turnaround) {
805         sprintf(buf, " avg_turnaround=%.15e,", avg_turnaround);
806         strcat(updates, buf);
807     }
808     if (strcmp(host_cpid, h.host_cpid)) {
809         escape_string(host_cpid, sizeof(host_cpid));
810         sprintf(buf, " host_cpid='%s',", host_cpid);
811         unescape_string(host_cpid, sizeof(host_cpid));
812         strcat(updates, buf);
813     }
814     if (strcmp(external_ip_addr, h.external_ip_addr)) {
815         escape_string(external_ip_addr, sizeof(external_ip_addr));
816         sprintf(buf, " external_ip_addr='%s',", external_ip_addr);
817         unescape_string(external_ip_addr, sizeof(external_ip_addr));
818         strcat(updates, buf);
819     }
820 #if 0
821     if (max_results_day != h.max_results_day) {
822         sprintf(buf, " max_results_day=%d,", max_results_day);
823         strcat(updates, buf);
824     }
825 #endif
826     if (strcmp(product_name, h.product_name)) {
827         escape_string(product_name, sizeof(product_name));
828         sprintf(buf, " product_name='%s',", product_name);
829         unescape_string(product_name, sizeof(product_name));
830         strcat(updates, buf);
831     }
832     if (gpu_active_frac != h.gpu_active_frac) {
833         sprintf(buf, " gpu_active_frac=%.15e,", gpu_active_frac);
834         strcat(updates, buf);
835     }
836     if (p_ngpus != h.p_ngpus) {
837         sprintf(buf, " p_ngpus=%d,", p_ngpus);
838         strcat(updates, buf);
839     }
840     if (p_gpu_fpops != h.p_gpu_fpops) {
841         sprintf(buf, " p_gpu_fpops=%.15e,", p_gpu_fpops);
842         strcat(updates, buf);
843     }
844 
845     int n = strlen(updates);
846     if (n == 0) return 0;
847     updates[n-1] = 0;        // trim the final comma
848     sprintf(query, "update host set %s where id=%lu", updates, id);
849     return db->do_query(query);
850 }
851 
fpops_percentile(double percentile,double & fpops)852 int DB_HOST::fpops_percentile(double percentile, double& fpops) {
853     char query[256];
854     int retval;
855     long n;
856 
857     sprintf(query, "where expavg_credit>10");
858     retval = count(n, query);
859     if (retval) return retval;
860     if (n==0) return ERR_NULL;
861     int m = (int)(n*percentile/100.);
862     sprintf(query,
863         "select p_fpops from host where expavg_credit>10 order by p_fpops limit %d,1",
864         m
865     );
866     return db->get_double(query, fpops);
867 }
868 
fpops_mean(double & mean)869 int DB_HOST::fpops_mean(double& mean) {
870     char query[256];
871     sprintf(query,
872         "select avg(p_fpops) from host where expavg_credit>10"
873     );
874     return db->get_double(query, mean);
875 }
876 
fpops_stddev(double & stddev)877 int DB_HOST::fpops_stddev(double& stddev) {
878     char query[256];
879     sprintf(query,
880         "select stddev(p_fpops) from host where expavg_credit>10"
881     );
882     return db->get_double(query, stddev);
883 }
884 
db_print(char * buf)885 void DB_WORKUNIT::db_print(char* buf){
886     sprintf(buf,
887         "create_time=%d, appid=%lu, "
888         "name='%s', xml_doc='%s', batch=%d, "
889         "rsc_fpops_est=%.15e, rsc_fpops_bound=%.15e, "
890         "rsc_memory_bound=%.15e, rsc_disk_bound=%.15e, "
891         "need_validate=%d, "
892         "canonical_resultid=%lu, canonical_credit=%.15e, "
893         "transition_time=%d, delay_bound=%d, "
894         "error_mask=%d, file_delete_state=%d, assimilate_state=%d, "
895         "hr_class=%d, opaque=%.15e, "
896         "min_quorum=%d, target_nresults=%d, max_error_results=%d, "
897         "max_total_results=%d, max_success_results=%d, "
898         "result_template_file='%s', "
899         "priority=%d, "
900         "rsc_bandwidth_bound=%.15e, "
901         "fileset_id=%lu, "
902         "app_version_id=%ld, "
903         "transitioner_flags=%d, "
904         "size_class=%d ",
905         create_time, appid,
906         name, xml_doc, batch,
907         rsc_fpops_est, rsc_fpops_bound, rsc_memory_bound, rsc_disk_bound,
908         need_validate,
909         canonical_resultid, canonical_credit,
910         transition_time, delay_bound,
911         error_mask, file_delete_state, assimilate_state,
912         hr_class, opaque,
913         min_quorum,
914         target_nresults,
915         max_error_results,
916         max_total_results,
917         max_success_results,
918         result_template_file,
919         priority,
920         rsc_bandwidth_bound,
921         fileset_id,
922         app_version_id,
923         transitioner_flags,
924         size_class
925     );
926 }
927 
db_print_values(char * buf)928 void DB_WORKUNIT::db_print_values(char* buf) {
929     sprintf(buf,
930         "(0, %d, %lu, "
931         "'%s', '%s', %d, "
932         "%f, %f, "
933         "%f, %f, "
934         "%d, "
935         "%lu, %f, "
936         "%d, %d, "
937         "%d, %d, %d, "
938         "%d, %f, "
939         "%d, %d, %d, "
940         "%d, %d, "
941         "'%s', "
942         "%d, NOW(), "
943         "%f, "
944         "%lu, "
945         "%ld, "
946         "%d, "
947         "%d)",
948         create_time, appid,
949         name, xml_doc, batch,
950         rsc_fpops_est, rsc_fpops_bound,
951         rsc_memory_bound, rsc_disk_bound,
952         need_validate,
953         canonical_resultid, canonical_credit,
954         transition_time, delay_bound,
955         error_mask, file_delete_state, assimilate_state,
956         hr_class, opaque,
957         min_quorum,
958         target_nresults,
959         max_error_results,
960         max_total_results,
961         max_success_results,
962         result_template_file,
963         priority,
964         rsc_bandwidth_bound,
965         fileset_id,
966         app_version_id,
967         transitioner_flags,
968         size_class
969     );
970 }
971 
db_parse(MYSQL_ROW & r)972 void DB_WORKUNIT::db_parse(MYSQL_ROW &r) {
973     int i=0;
974     clear();
975     id = atol(r[i++]);
976     create_time = atoi(r[i++]);
977     appid = atol(r[i++]);
978     strcpy2(name, r[i++]);
979     strcpy2(xml_doc, r[i++]);
980     batch = atoi(r[i++]);
981     rsc_fpops_est = atof(r[i++]);
982     rsc_fpops_bound = atof(r[i++]);
983     rsc_memory_bound = atof(r[i++]);
984     rsc_disk_bound = atof(r[i++]);
985     need_validate = atoi(r[i++]);
986     canonical_resultid = atol(r[i++]);
987     canonical_credit = atof(r[i++]);
988     transition_time = atoi(r[i++]);
989     delay_bound = atoi(r[i++]);
990     error_mask = atoi(r[i++]);
991     file_delete_state = atoi(r[i++]);
992     assimilate_state = atoi(r[i++]);
993     hr_class = atoi(r[i++]);
994     opaque = atof(r[i++]);
995     min_quorum = atoi(r[i++]);
996     target_nresults = atoi(r[i++]);
997     max_error_results = atoi(r[i++]);
998     max_total_results = atoi(r[i++]);
999     max_success_results = atoi(r[i++]);
1000     strcpy2(result_template_file, r[i++]);
1001     priority = atoi(r[i++]);
1002     strcpy2(mod_time, r[i++]);
1003     rsc_bandwidth_bound = atof(r[i++]);
1004     fileset_id = atol(r[i++]);
1005     app_version_id = atol(r[i++]);
1006     transitioner_flags = atoi(r[i++]);
1007     size_class = atoi(r[i++]);
1008 }
1009 
db_print(char * buf)1010 void DB_CREDITED_JOB::db_print(char* buf){
1011     sprintf(buf,
1012         "userid=%lu, workunitid=%lu",
1013         userid, workunitid
1014     );
1015 }
1016 
db_parse(MYSQL_ROW & r)1017 void DB_CREDITED_JOB::db_parse(MYSQL_ROW &r) {
1018     int i=0;
1019     clear();
1020     userid = atol(r[i++]);
1021     workunitid = atol(r[i++]);
1022 };
1023 
db_print(char * buf)1024 void DB_RESULT::db_print(char* buf){
1025     ESCAPE(xml_doc_out);
1026     ESCAPE(stderr_out);
1027     sprintf(
1028         buf,
1029         "create_time=%d, workunitid=%lu, "
1030         "server_state=%d, outcome=%d, client_state=%d, "
1031         "hostid=%lu, userid=%lu, "
1032         "report_deadline=%d, sent_time=%d, received_time=%d, "
1033         "name='%s', cpu_time=%.15e, "
1034         "xml_doc_in='%s', xml_doc_out='%s', stderr_out='%s', "
1035         "batch=%d, file_delete_state=%d, validate_state=%d, "
1036         "claimed_credit=%.15e, granted_credit=%.15e, opaque=%.15e, random=%d, "
1037         "app_version_num=%d, appid=%lu, exit_status=%d, teamid=%lu, "
1038         "priority=%d, elapsed_time=%.15e, flops_estimate=%.15e, "
1039         "app_version_id=%ld, runtime_outlier=%d, size_class=%d, "
1040         "peak_working_set_size=%.0f, "
1041         "peak_swap_size=%.0f, "
1042         "peak_disk_usage=%.0f ",
1043         create_time, workunitid,
1044         server_state, outcome, client_state,
1045         hostid, userid,
1046         report_deadline, sent_time, received_time,
1047         name, cpu_time,
1048         xml_doc_in, xml_doc_out, stderr_out,
1049         batch, file_delete_state, validate_state,
1050         claimed_credit, granted_credit, opaque, random,
1051         app_version_num, appid, exit_status, teamid,
1052         priority, elapsed_time, flops_estimate,
1053         app_version_id,
1054         runtime_outlier?1:0,
1055         size_class,
1056         peak_working_set_size,
1057         peak_swap_size,
1058         peak_disk_usage
1059     );
1060     UNESCAPE(xml_doc_out);
1061     UNESCAPE(stderr_out);
1062 }
1063 
1064 // the following used for "batch insert" from transitioner
1065 //
db_print_values(char * buf)1066 void DB_RESULT::db_print_values(char* buf){
1067     ESCAPE(xml_doc_out);
1068     ESCAPE(stderr_out);
1069     sprintf(
1070         buf,
1071         "(0, %d, %lu, "
1072         "%d, %d, %d, "
1073         "%lu, %lu, "
1074         "%d, %d, %d, "
1075         "'%s', %.15e, "
1076         "'%s', '%s', '%s', "
1077         "%d, %d, %d, "
1078         "%.15e, %.15e, %.15e, %d, "
1079         "%d, %lu, %d, %lu, %d, NOW(), 0, 0, 0, 0, %d, 0, 0, 0)",
1080         create_time, workunitid,
1081         server_state, outcome, client_state,
1082         hostid, userid,
1083         report_deadline, sent_time, received_time,
1084         name, cpu_time,
1085         xml_doc_in, xml_doc_out, stderr_out,
1086         batch, file_delete_state, validate_state,
1087         claimed_credit, granted_credit, opaque, random,
1088         app_version_num, appid, exit_status, teamid, priority, size_class
1089     );
1090     UNESCAPE(xml_doc_out);
1091     UNESCAPE(stderr_out);
1092 }
1093 
1094 // called from scheduler when dispatch this result.
1095 // The "... and server_state=%d" is a safeguard against
1096 // the case where another scheduler tries to send this result at the same time
1097 //
mark_as_sent(int old_server_state,int report_grace_period)1098 int DB_RESULT::mark_as_sent(int old_server_state, int report_grace_period) {
1099     char query[MAX_QUERY_LEN];
1100     int retval;
1101 
1102     sprintf(query,
1103         "update result set server_state=%d, hostid=%lu, userid=%lu, sent_time=%d, report_deadline=%d, flops_estimate=%.15e, app_version_id=%ld  where id=%lu and server_state=%d",
1104         server_state,
1105         hostid,
1106         userid,
1107         sent_time,
1108         report_deadline + report_grace_period,
1109         flops_estimate,
1110         app_version_id,
1111         id,
1112         old_server_state
1113     );
1114     retval = db->do_query(query);
1115     if (retval) return retval;
1116     if (db->affected_rows() != 1) return ERR_DB_NOT_FOUND;
1117     return 0;
1118 }
1119 
db_parse(MYSQL_ROW & r)1120 void DB_RESULT::db_parse(MYSQL_ROW &r) {
1121     int i=0;
1122     clear();
1123     id = atol(r[i++]);
1124     create_time = atoi(r[i++]);
1125     workunitid = atol(r[i++]);
1126     server_state = atoi(r[i++]);
1127     outcome = atoi(r[i++]);
1128     client_state = atoi(r[i++]);
1129     hostid = atol(r[i++]);
1130     userid = atol(r[i++]);
1131     report_deadline = atoi(r[i++]);
1132     sent_time = atoi(r[i++]);
1133     received_time = atoi(r[i++]);
1134     strcpy2(name, r[i++]);
1135     cpu_time = atof(r[i++]);
1136     strcpy2(xml_doc_in, r[i++]);
1137     strcpy2(xml_doc_out, r[i++]);
1138     strcpy2(stderr_out, r[i++]);
1139     batch = atoi(r[i++]);
1140     file_delete_state = atoi(r[i++]);
1141     validate_state = atoi(r[i++]);
1142     claimed_credit = atof(r[i++]);
1143     granted_credit = atof(r[i++]);
1144     opaque = atof(r[i++]);
1145     random = atoi(r[i++]);
1146     app_version_num = atoi(r[i++]);
1147     appid = atol(r[i++]);
1148     exit_status = atoi(r[i++]);
1149     teamid = atol(r[i++]);
1150     priority = atoi(r[i++]);
1151     strcpy2(mod_time, r[i++]);
1152     elapsed_time = atof(r[i++]);
1153     flops_estimate = atof(r[i++]);
1154     app_version_id = atol(r[i++]);
1155     runtime_outlier = (atoi(r[i++]) != 0);
1156     size_class = atoi(r[i++]);
1157     peak_working_set_size = atof(r[i++]);
1158     peak_swap_size = atof(r[i++]);
1159     peak_disk_usage = atof(r[i++]);
1160 }
1161 
1162 // faster version.
1163 // return unsent count up to a max of "count_max"
1164 //
get_unsent_counts(APP & app,int * unsent_count,int count_max)1165 int DB_RESULT::get_unsent_counts(APP& app, int* unsent_count, int count_max) {
1166     char query[1024];
1167     int retval;
1168     MYSQL_RES *rp;
1169 
1170     for (int i=0; i<app.n_size_classes; i++) {
1171         sprintf(query,
1172             "select id from result where appid=%lu and server_state=%d and size_class=%d limit %d",
1173             app.id, RESULT_SERVER_STATE_UNSENT, i, count_max
1174         );
1175         retval = db->do_query(query);
1176         if (retval) return mysql_errno(db->mysql);
1177         rp = mysql_store_result(db->mysql);
1178         if (!rp) return mysql_errno(db->mysql);
1179         int count = 0;
1180         while (1) {
1181             MYSQL_ROW row = mysql_fetch_row(rp);
1182             if (!row) break;
1183             count++;
1184         }
1185         mysql_free_result(rp);
1186         unsent_count[i] = count;
1187     }
1188     return 0;
1189 }
1190 
1191 #if 0
1192 // the following is too slow if result table is large.
1193 //
1194 int DB_RESULT::get_unsent_counts(APP& app, int* unsent_count) {
1195     char query[1024];
1196     MYSQL_RES *rp;
1197 
1198     for (int i=0; i<app.n_size_classes; i++) {
1199         unsent_count[i] = 0;
1200     }
1201 
1202     sprintf(query,
1203         "select size_class, count(size_class) from result where appid=%lu and server_state=%d group by size_class",
1204         app.id, RESULT_SERVER_STATE_UNSENT
1205     );
1206     int retval = db->do_query(query);
1207     if (retval) return mysql_errno(db->mysql);
1208     rp = mysql_store_result(db->mysql);
1209     if (!rp) return mysql_errno(db->mysql);
1210     while (1) {
1211         MYSQL_ROW row = mysql_fetch_row(rp);
1212         if (!row) break;
1213         int sc = atoi(row[0]);
1214         int count = atoi(row[1]);
1215         if (sc >= app.n_size_classes) {
1216             fprintf(stderr, "size class %d too large\n", sc);
1217             retval = -1;
1218             break;
1219         }
1220         unsent_count[sc] = count;
1221     };
1222     mysql_free_result(rp);
1223     return retval;
1224 }
1225 #endif
1226 
make_unsent(APP & app,int size_class,int n,const char * order_clause,int & nchanged)1227 int DB_RESULT::make_unsent(
1228     APP& app, int size_class, int n, const char* order_clause, int& nchanged
1229 ) {
1230     char query[1024];
1231     sprintf(query,
1232         "update result set server_state=%d where appid=%lu and server_state=%d and size_class=%d %s limit %d",
1233         RESULT_SERVER_STATE_UNSENT,
1234         app.id,
1235         RESULT_SERVER_STATE_INACTIVE,
1236         size_class,
1237         order_clause,
1238         n
1239     );
1240     int retval = db->do_query(query);
1241     if (retval) return mysql_errno(db->mysql);
1242     nchanged = db->affected_rows();
1243     return 0;
1244 }
1245 
db_print(char * buf)1246 void DB_MSG_FROM_HOST::db_print(char* buf) {
1247     ESCAPE(xml);
1248     ESCAPE(variety);
1249     sprintf(buf,
1250         "create_time=%d, "
1251         "hostid=%lu, variety='%s', "
1252         "handled=%d, xml='%s'",
1253 
1254         create_time,
1255         hostid, variety,
1256         handled, xml
1257 
1258     );
1259     UNESCAPE(xml);
1260     UNESCAPE(variety);
1261 }
1262 
db_parse(MYSQL_ROW & r)1263 void DB_MSG_FROM_HOST::db_parse(MYSQL_ROW& r) {
1264     int i=0;
1265     clear();
1266     id = atol(r[i++]);
1267     create_time = atoi(r[i++]);
1268     hostid = atol(r[i++]);
1269     strcpy2(variety, r[i++]);
1270     handled = atoi(r[i++]);
1271     strcpy2(xml, r[i++]);
1272 }
1273 
db_print(char * buf)1274 void DB_MSG_TO_HOST::db_print(char* buf) {
1275     ESCAPE(xml);
1276     ESCAPE(variety);
1277     sprintf(buf,
1278         "create_time=%d, "
1279         "hostid=%lu, variety='%s', "
1280         "handled=%d, xml='%s'",
1281         create_time,
1282         hostid, variety,
1283         handled, xml
1284     );
1285     UNESCAPE(xml);
1286     UNESCAPE(variety);
1287 }
1288 
db_parse(MYSQL_ROW & r)1289 void DB_MSG_TO_HOST::db_parse(MYSQL_ROW& r) {
1290     int i=0;
1291     clear();
1292     id = atol(r[i++]);
1293     create_time = atoi(r[i++]);
1294     hostid = atol(r[i++]);
1295     strcpy2(variety, r[i++]);
1296     handled = atoi(r[i++]);
1297     strcpy2(xml, r[i++]);
1298 }
1299 
db_print(char * buf)1300 void DB_ASSIGNMENT::db_print(char* buf) {
1301     sprintf(buf,
1302         "create_time=%d, "
1303         "target_id=%lu, "
1304         "target_type=%d, "
1305         "multi=%d, "
1306         "workunitid=%lu, "
1307         "resultid=%lu",
1308         create_time,
1309         target_id,
1310         target_type,
1311         multi,
1312         workunitid,
1313         _resultid
1314     );
1315 }
1316 
db_parse(MYSQL_ROW & r)1317 void DB_ASSIGNMENT::db_parse(MYSQL_ROW& r) {
1318     int i=0;
1319     clear();
1320     id = atol(r[i++]);
1321     create_time = atoi(r[i++]);
1322     target_id = atol(r[i++]);
1323     target_type = atoi(r[i++]);
1324     multi = atoi(r[i++]);
1325     workunitid = atol(r[i++]);
1326     _resultid = atol(r[i++]);
1327 }
1328 
update_scheduler(DB_HOST_APP_VERSION & orig)1329 int DB_HOST_APP_VERSION::update_scheduler(DB_HOST_APP_VERSION& orig) {
1330     char query[1024], clause[512];
1331 
1332     if (consecutive_valid == orig.consecutive_valid
1333         && max_jobs_per_day == orig.max_jobs_per_day
1334         && n_jobs_today == orig.n_jobs_today
1335     ) {
1336         return 0;
1337     }
1338     sprintf(query,
1339         "consecutive_valid=%d, max_jobs_per_day=%d, n_jobs_today=%d",
1340         consecutive_valid,
1341         max_jobs_per_day,
1342         n_jobs_today
1343     );
1344     sprintf(clause,
1345         "host_id=%lu and app_version_id=%ld",
1346         host_id, app_version_id
1347     );
1348     return update_fields_noid(query, clause);
1349 }
1350 
update_validator(DB_HOST_APP_VERSION & orig)1351 int DB_HOST_APP_VERSION::update_validator(DB_HOST_APP_VERSION& orig) {
1352     char query[8192], clause[512];
1353 
1354     if (pfc.n == orig.pfc.n
1355         && pfc.avg == orig.pfc.avg
1356         && et.n == orig.et.n
1357         && et.avg == orig.et.avg
1358         && et.q == orig.et.q
1359         && et.var == orig.et.var
1360         && turnaround.n == orig.turnaround.n
1361         && turnaround.avg == orig.turnaround.avg
1362         && turnaround.q == orig.turnaround.q
1363         && turnaround.var == orig.turnaround.var
1364         && consecutive_valid == orig.consecutive_valid
1365         && max_jobs_per_day == orig.max_jobs_per_day
1366     ) {
1367         return 0;
1368     }
1369     sprintf(query,
1370         "pfc_n=%.15e, "
1371         "pfc_avg=%.15e, "
1372         "et_n=%.15e, "
1373         "et_avg=%.15e, "
1374         "et_q=%.15e, "
1375         "et_var=%.15e, "
1376         "turnaround_n=%.15e, "
1377         "turnaround_avg=%.15e, "
1378         "turnaround_q=%.15e, "
1379         "turnaround_var=%.15e, "
1380         "consecutive_valid=%d, "
1381         "max_jobs_per_day=%d ",
1382         pfc.n,
1383         pfc.avg,
1384         et.n,
1385         et.avg,
1386         et.q,
1387         et.var,
1388         turnaround.n,
1389         turnaround.avg,
1390         turnaround.q,
1391         turnaround.var,
1392         consecutive_valid,
1393         max_jobs_per_day
1394     );
1395     sprintf(clause,
1396         "host_id=%lu and app_version_id=%ld ",
1397         host_id, app_version_id
1398     );
1399     return update_fields_noid(query, clause);
1400 }
1401 
db_print(char * buf)1402 void DB_HOST_APP_VERSION::db_print(char* buf) {
1403     sprintf(buf,
1404         "host_id=%lu, "
1405         "app_version_id=%ld, "
1406         "pfc_n=%.15e, "
1407         "pfc_avg=%.15e, "
1408         "et_n=%.15e, "
1409         "et_avg=%.15e, "
1410         "et_var=%.15e, "
1411         "et_q=%.15e, "
1412         "max_jobs_per_day=%d, "
1413         "n_jobs_today=%d, "
1414         "turnaround_n=%.15e, "
1415         "turnaround_avg=%.15e, "
1416         "turnaround_var=%.15e, "
1417         "turnaround_q=%.15e, "
1418         "consecutive_valid=%d ",
1419         host_id,
1420         app_version_id,
1421         pfc.n,
1422         pfc.avg,
1423         et.n,
1424         et.avg,
1425         et.var,
1426         et.q,
1427         max_jobs_per_day,
1428         n_jobs_today,
1429         turnaround.n,
1430         turnaround.avg,
1431         turnaround.var,
1432         turnaround.q,
1433         consecutive_valid
1434     );
1435 }
1436 
db_parse(MYSQL_ROW & r)1437 void DB_HOST_APP_VERSION::db_parse(MYSQL_ROW& r) {
1438     int i=0;
1439     clear();
1440     host_id = atol(r[i++]);
1441     app_version_id = atol(r[i++]);
1442     pfc.n = atof(r[i++]);
1443     pfc.avg = atof(r[i++]);
1444     et.n = atof(r[i++]);
1445     et.avg = atof(r[i++]);
1446     et.var = atof(r[i++]);
1447     et.q = atof(r[i++]);
1448     max_jobs_per_day = atoi(r[i++]);
1449     n_jobs_today = atoi(r[i++]);
1450     turnaround.n = atof(r[i++]);
1451     turnaround.avg = atof(r[i++]);
1452     turnaround.var = atof(r[i++]);
1453     turnaround.q = atof(r[i++]);
1454     consecutive_valid = atoi(r[i++]);
1455 }
1456 
db_print(char * buf)1457 void DB_USER_SUBMIT::db_print(char* buf) {
1458     sprintf(buf,
1459         "user_id=%lu, "
1460         "quota=%.15e, "
1461         "logical_start_time=%.15e, "
1462         "submit_all=%d, "
1463         "manage_all=%d ",
1464         user_id,
1465         quota,
1466         logical_start_time,
1467         submit_all?1:0,
1468         manage_all?1:0
1469     );
1470 }
1471 
db_parse(MYSQL_ROW & r)1472 void DB_USER_SUBMIT::db_parse(MYSQL_ROW& r) {
1473     int i=0;
1474     clear();
1475     user_id = atol(r[i++]);
1476     quota = atof(r[i++]);
1477     logical_start_time = atof(r[i++]);
1478     submit_all = (atoi(r[i++]) != 0);
1479     manage_all = (atoi(r[i++]) != 0);
1480 }
1481 
db_print(char * buf)1482 void DB_STATE_COUNTS::db_print(char* buf) {
1483     sprintf(buf,
1484         "appid=%lu, "
1485         "last_update_time=%d, "
1486         "result_server_state_2=%d, "
1487         "result_server_state_4=%d, "
1488         "result_file_delete_state_1=%d, "
1489         "result_file_delete_state_2=%d, "
1490         "result_server_state_5_and_file_delete_state_0=%d, "
1491         "workunit_need_validate_1=%d, "
1492         "workunit_assimilate_state_1=%d, "
1493         "workunit_file_delete_state_1=%d, "
1494         "workunit_file_delete_state_2=%d, ",
1495         appid,
1496         last_update_time,
1497         result_server_state_2,
1498         result_server_state_4,
1499         result_file_delete_state_1,
1500         result_file_delete_state_2,
1501         result_server_state_5_and_file_delete_state_0,
1502         workunit_need_validate_1,
1503         workunit_assimilate_state_1,
1504         workunit_file_delete_state_1,
1505         workunit_file_delete_state_2
1506     );
1507 }
1508 
db_parse(MYSQL_ROW & r)1509 void DB_STATE_COUNTS::db_parse(MYSQL_ROW& r) {
1510     int i=0;
1511     clear();
1512     appid = atoi(r[i++]);
1513     last_update_time = atoi(r[i++]);
1514     result_server_state_2 = atoi(r[i++]);
1515     result_server_state_4 = atoi(r[i++]);
1516     result_file_delete_state_1 = atoi(r[i++]);
1517     result_file_delete_state_2 = atoi(r[i++]);
1518     result_server_state_5_and_file_delete_state_0 = atoi(r[i++]);
1519     workunit_need_validate_1 = atoi(r[i++]);
1520     workunit_assimilate_state_1 = atoi(r[i++]);
1521     workunit_file_delete_state_1 = atoi(r[i++]);
1522     workunit_file_delete_state_2 = atoi(r[i++]);
1523 }
1524 
parse(MYSQL_ROW & r)1525 void TRANSITIONER_ITEM::parse(MYSQL_ROW& r) {
1526     int i=0;
1527     clear();
1528     id = atol(r[i++]);
1529     strcpy2(name, r[i++]);
1530     appid = atol(r[i++]);
1531     min_quorum = atoi(r[i++]);
1532     need_validate = atoi(r[i++]);
1533     canonical_resultid = atol(r[i++]);
1534     transition_time = atoi(r[i++]);
1535     delay_bound = atoi(r[i++]);
1536     error_mask = atoi(r[i++]);
1537     max_error_results = atoi(r[i++]);
1538     max_total_results = atoi(r[i++]);
1539     file_delete_state = atoi(r[i++]);
1540     assimilate_state = atoi(r[i++]);
1541     target_nresults = atoi(r[i++]);
1542     strcpy2(result_template_file, r[i++]);
1543     priority = atoi(r[i++]);
1544     hr_class = atoi(r[i++]);
1545     batch = atoi(r[i++]);
1546     app_version_id = atol(r[i++]);
1547     transitioner_flags = atoi(r[i++]);
1548     size_class = atoi(r[i++]);
1549 
1550     // use safe_atoi() from here on cuz they might not be there
1551     //
1552     res_id = safe_atol(r[i++]);
1553     strcpy2(res_name, r[i++]);
1554     res_report_deadline = safe_atoi(r[i++]);
1555     res_server_state = safe_atoi(r[i++]);
1556     res_outcome = safe_atoi(r[i++]);
1557     res_validate_state = safe_atoi(r[i++]);
1558     res_file_delete_state = safe_atoi(r[i++]);
1559     res_sent_time = safe_atoi(r[i++]);
1560     res_hostid = safe_atol(r[i++]);
1561     res_received_time = safe_atoi(r[i++]);
1562     res_app_version_id = safe_atol(r[i++]);
1563     res_exit_status = safe_atoi(r[i++]);
1564 }
1565 
enumerate(int transition_time,int nresult_limit,int wu_id_modulus,int wu_id_remainder,std::vector<TRANSITIONER_ITEM> & items)1566 int DB_TRANSITIONER_ITEM_SET::enumerate(
1567     int transition_time, int nresult_limit,
1568     int wu_id_modulus, int wu_id_remainder,
1569     std::vector<TRANSITIONER_ITEM>& items
1570 ) {
1571     int retval;
1572     char query[MAX_QUERY_LEN];
1573     char mod_clause[256];;
1574     char time_clause[256];
1575     MYSQL_ROW row;
1576     TRANSITIONER_ITEM new_item;
1577 
1578     if (!cursor.active) {
1579         sprintf(time_clause, " wu.transition_time < %d ", transition_time);
1580         if (wu_id_modulus) {
1581             // terrible kludge: if rem >= mod, treat it as a WU ID
1582             // This is to support the --wu_id debugging feature
1583             //
1584             if (wu_id_remainder < wu_id_modulus) {
1585                 sprintf(mod_clause,
1586                     " and wu.id %% %d = %d ",
1587                     wu_id_modulus, wu_id_remainder
1588                 );
1589             } else {
1590                 sprintf(mod_clause, " and wu.id = %u ", wu_id_remainder);
1591                 strcpy(time_clause, " true ");
1592             }
1593         } else {
1594             strcpy(mod_clause, "");
1595         }
1596 
1597 
1598         sprintf(query,
1599             "SELECT "
1600             "   wu.id, "
1601             "   wu.name, "
1602             "   wu.appid, "
1603             "   wu.min_quorum, "
1604             "   wu.need_validate, "
1605             "   wu.canonical_resultid, "
1606             "   wu.transition_time, "
1607             "   wu.delay_bound, "
1608             "   wu.error_mask, "
1609             "   wu.max_error_results, "
1610             "   wu.max_total_results, "
1611             "   wu.file_delete_state, "
1612             "   wu.assimilate_state, "
1613             "   wu.target_nresults, "
1614             "   wu.result_template_file, "
1615             "   wu.priority, "
1616             "   wu.hr_class, "
1617             "   wu.batch, "
1618             "   wu.app_version_id, "
1619             "   wu.transitioner_flags, "
1620             "   wu.size_class, "
1621             "   res.id, "
1622             "   res.name, "
1623             "   res.report_deadline, "
1624             "   res.server_state, "
1625             "   res.outcome, "
1626             "   res.validate_state, "
1627             "   res.file_delete_state, "
1628             "   res.sent_time, "
1629             "   res.hostid, "
1630             "   res.received_time, "
1631             "   res.app_version_id, "
1632             "   res.exit_status "
1633             "FROM "
1634             "   workunit AS wu "
1635             "       LEFT JOIN result AS res ON wu.id = res.workunitid "
1636             "WHERE "
1637             "   %s %s and transitioner_flags<>%d "
1638             "LIMIT "
1639             "   %d ",
1640             time_clause, mod_clause, TRANSITION_NONE, nresult_limit
1641         );
1642 
1643         retval = db->do_query(query);
1644         if (retval) return mysql_errno(db->mysql);
1645 
1646         // the following stores the entire result set in memory
1647         //
1648         cursor.rp = mysql_store_result(db->mysql);
1649         if (!cursor.rp) return mysql_errno(db->mysql);
1650         cursor.active = true;
1651 
1652         row = mysql_fetch_row(cursor.rp);
1653         if (!row) {
1654             mysql_free_result(cursor.rp);
1655             cursor.active = false;
1656             retval = mysql_errno(db->mysql);
1657             if (retval) return ERR_DB_CONN_LOST;
1658             return ERR_DB_NOT_FOUND;
1659         }
1660         last_item.parse(row);
1661         nitems_this_query = 1;
1662     }
1663 
1664     items.clear();
1665     while (true) {
1666         items.push_back(last_item);
1667         row = mysql_fetch_row(cursor.rp);
1668         if (!row) {
1669             mysql_free_result(cursor.rp);
1670             cursor.active = false;
1671 
1672             // if got fewer rows than requested, last group is complete
1673             //
1674             if (nitems_this_query < nresult_limit) {
1675                 return 0;
1676             } else {
1677                 return ERR_DB_NOT_FOUND;
1678             }
1679         }
1680         new_item.parse(row);
1681         nitems_this_query++;
1682         if (new_item.id != last_item.id) {
1683             last_item = new_item;
1684             return 0;
1685         }
1686         last_item = new_item;
1687     }
1688 
1689     return 0;
1690 }
1691 
update_result(TRANSITIONER_ITEM & ti)1692 int DB_TRANSITIONER_ITEM_SET::update_result(TRANSITIONER_ITEM& ti) {
1693     char query[MAX_QUERY_LEN];
1694 
1695     sprintf(query,
1696         "update result set server_state=%d, outcome=%d, "
1697         "validate_state=%d, file_delete_state=%d where id=%lu",
1698         ti.res_server_state,
1699         ti.res_outcome,
1700         ti.res_validate_state,
1701         ti.res_file_delete_state,
1702         ti.res_id
1703     );
1704     int retval = db->do_query(query);
1705     if (db->affected_rows() != 1) return ERR_DB_NOT_FOUND;
1706     return retval;
1707 }
1708 
update_workunit(TRANSITIONER_ITEM & ti,TRANSITIONER_ITEM & ti_original)1709 int DB_TRANSITIONER_ITEM_SET::update_workunit(
1710     TRANSITIONER_ITEM& ti, TRANSITIONER_ITEM& ti_original
1711 ) {
1712     char query[MAX_QUERY_LEN];
1713     char updates[4096], buf[256];
1714 
1715     strcpy(updates, "");
1716     if (ti.need_validate != ti_original.need_validate) {
1717         sprintf(buf, " need_validate=%d,", ti.need_validate);
1718         strcat(updates, buf);
1719     }
1720     if (ti.error_mask != ti_original.error_mask) {
1721         sprintf(buf, " error_mask=%d,", ti.error_mask);
1722         strcat(updates, buf);
1723     }
1724     if (ti.assimilate_state != ti_original.assimilate_state) {
1725         sprintf(buf, " assimilate_state=%d,", ti.assimilate_state);
1726         strcat(updates, buf);
1727     }
1728     if (ti.file_delete_state != ti_original.file_delete_state) {
1729         sprintf(buf, " file_delete_state=%d,", ti.file_delete_state);
1730         strcat(updates, buf);
1731     }
1732     if (ti.transition_time != ti_original.transition_time) {
1733         sprintf(buf, " transition_time=%d,", ti.transition_time);
1734         strcat(updates, buf);
1735     }
1736     if (ti.hr_class != ti_original.hr_class) {
1737         sprintf(buf, " hr_class=%d,", ti.hr_class);
1738         strcat(updates, buf);
1739     }
1740     if (ti.app_version_id != ti_original.app_version_id) {
1741         sprintf(buf, " app_version_id=%lu,", ti.app_version_id);
1742         strcat(updates, buf);
1743     }
1744     int n = strlen(updates);
1745     if (n == 0) {
1746         return 0;
1747     }
1748 
1749     // trim the final comma
1750     //
1751     updates[n-1] = 0;
1752 
1753     sprintf(query, "update workunit set %s where id=%lu", updates, ti.id);
1754     return db->do_query(query);
1755 }
1756 
parse(MYSQL_ROW & r)1757 void VALIDATOR_ITEM::parse(MYSQL_ROW& r) {
1758     int i=0;
1759     clear();
1760     wu.id = atol(r[i++]);
1761     strcpy2(wu.name, r[i++]);
1762     wu.canonical_resultid = atol(r[i++]);
1763     wu.canonical_credit = atof(r[i++]);
1764     wu.min_quorum = atoi(r[i++]);
1765     wu.assimilate_state = atoi(r[i++]);
1766     wu.transition_time = atoi(r[i++]);
1767     wu.opaque = atof(r[i++]);
1768     wu.batch = atoi(r[i++]);
1769     wu.target_nresults = atoi(r[i++]);
1770     wu.max_success_results = atoi(r[i++]);
1771     wu.error_mask = atoi(r[i++]);
1772     wu.rsc_fpops_est = atof(r[i++]);
1773     wu.rsc_fpops_bound = atof(r[i++]);
1774 
1775     res.id = atol(r[i++]);
1776     res.workunitid = atol(r[i++]);
1777     strcpy2(res.name, r[i++]);
1778     res.validate_state = atoi(r[i++]);
1779     res.server_state = atoi(r[i++]);
1780     res.outcome = atoi(r[i++]);
1781     res.granted_credit = atof(r[i++]);
1782     strcpy2(res.xml_doc_in, r[i++]);
1783     strcpy2(res.xml_doc_out, r[i++]);
1784     strcpy2(res.stderr_out, r[i++]);
1785     res.cpu_time = atof(r[i++]);
1786     res.batch = atoi(r[i++]);
1787     res.opaque = atof(r[i++]);
1788     res.exit_status = atoi(r[i++]);
1789     res.hostid = atol(r[i++]);
1790     res.userid = atol(r[i++]);
1791     res.teamid = atol(r[i++]);
1792     res.sent_time = atoi(r[i++]);
1793     res.received_time = atoi(r[i++]);
1794     res.appid = atol(r[i++]);
1795     res.app_version_id = atol(r[i++]);
1796     res.app_version_num = atoi(r[i++]);
1797     res.elapsed_time = atof(r[i++]);
1798     res.flops_estimate = atof(r[i++]);
1799     res.app_version_id = atol(r[i++]);
1800     res.runtime_outlier = (atoi(r[i++]) != 0);
1801 }
1802 
enumerate(DB_ID_TYPE appid,int nresult_limit,int wu_id_modulus,int wu_id_remainder,DB_ID_TYPE wu_id_min,DB_ID_TYPE wu_id_max,std::vector<VALIDATOR_ITEM> & items)1803 int DB_VALIDATOR_ITEM_SET::enumerate(
1804     DB_ID_TYPE appid, int nresult_limit,
1805     int wu_id_modulus, int wu_id_remainder,
1806     DB_ID_TYPE wu_id_min, DB_ID_TYPE wu_id_max,
1807     std::vector<VALIDATOR_ITEM>& items
1808 ) {
1809     int retval;
1810     char query[MAX_QUERY_LEN], mod_clause[256];
1811     char main_clause[256];
1812     MYSQL_ROW row;
1813     VALIDATOR_ITEM new_item;
1814 
1815     if (!cursor.active) {
1816         sprintf(main_clause,
1817             " and wu.appid = %lu and wu.need_validate > 0 ", appid
1818         );
1819         if (wu_id_modulus) {
1820             // terrible kludge: if rem >= mod, treat it as a WU ID
1821             // This is to support the --wu_id debugging feature
1822             //
1823             if (wu_id_remainder < wu_id_modulus) {
1824                 sprintf(mod_clause,
1825                     " and wu.id %% %d = %d ",
1826                     wu_id_modulus, wu_id_remainder
1827                 );
1828             } else {
1829                 sprintf(mod_clause, " and wu.id = %u ", wu_id_remainder);
1830                 strcpy(main_clause, "");
1831             }
1832         } else {
1833             strcpy(mod_clause, "");
1834         }
1835         if (wu_id_min) {
1836           sprintf(mod_clause+(strlen(mod_clause)), " and wu.id >= %lu", wu_id_min);
1837         }
1838         if (wu_id_max) {
1839           sprintf(mod_clause+(strlen(mod_clause)), " and wu.id <= %lu", wu_id_max);
1840         }
1841 
1842         sprintf(query,
1843             "SELECT "
1844             "   wu.id, "
1845             "   wu.name, "
1846             "   wu.canonical_resultid, "
1847             "   wu.canonical_credit, "
1848             "   wu.min_quorum, "
1849             "   wu.assimilate_state, "
1850             "   wu.transition_time, "
1851             "   wu.opaque, "
1852             "   wu.batch, "
1853             "   wu.target_nresults, "
1854             "   wu.max_success_results, "
1855             "   wu.error_mask, "
1856             "   wu.rsc_fpops_est, "
1857             "   wu.rsc_fpops_bound, "
1858             "   res.id, "
1859             "   res.workunitid, "
1860             "   res.name, "
1861             "   res.validate_state, "
1862             "   res.server_state, "
1863             "   res.outcome, "
1864             "   res.granted_credit, "
1865             "   res.xml_doc_in, "
1866             "   res.xml_doc_out, "
1867             "   res.stderr_out, "
1868             "   res.cpu_time, "
1869             "   res.batch, "
1870             "   res.opaque, "
1871             "   res.exit_status, "
1872             "   res.hostid, "
1873             "   res.userid, "
1874             "   res.teamid, "
1875             "   res.sent_time, "
1876             "   res.received_time, "
1877             "   res.appid, "
1878             "   res.app_version_id, "
1879             "   res.app_version_num, "
1880             "   res.elapsed_time, "
1881             "   res.flops_estimate, "
1882             "   res.app_version_id, "
1883             "   res.runtime_outlier "
1884             "FROM "
1885             "   workunit AS wu, result AS res where wu.id = res.workunitid "
1886             "   %s %s "
1887             "LIMIT "
1888             "   %d ",
1889             main_clause, mod_clause, nresult_limit
1890         );
1891 
1892         retval = db->do_query(query);
1893         if (retval) return mysql_errno(db->mysql);
1894 
1895         // the following stores the entire result set in memory
1896         cursor.rp = mysql_store_result(db->mysql);
1897         if (!cursor.rp) return mysql_errno(db->mysql);
1898         cursor.active = true;
1899 
1900         row = mysql_fetch_row(cursor.rp);
1901         if (!row) {
1902             mysql_free_result(cursor.rp);
1903             cursor.active = false;
1904             retval = mysql_errno(db->mysql);
1905             if (retval) return ERR_DB_CONN_LOST;
1906             return ERR_DB_NOT_FOUND;
1907         }
1908         last_item.parse(row);
1909         nitems_this_query = 1;
1910     }
1911 
1912     items.clear();
1913     while (true) {
1914         items.push_back(last_item);
1915         row = mysql_fetch_row(cursor.rp);
1916         if (!row) {
1917             mysql_free_result(cursor.rp);
1918             cursor.active = false;
1919 
1920             // if got fewer rows than requested, last group is complete
1921             //
1922             if (nitems_this_query < nresult_limit) {
1923                 return 0;
1924             } else {
1925                 return ERR_DB_NOT_FOUND;
1926             }
1927         }
1928         new_item.parse(row);
1929         nitems_this_query++;
1930         if (new_item.wu.id != last_item.wu.id) {
1931             last_item = new_item;
1932             return 0;
1933         }
1934         last_item = new_item;
1935     }
1936 
1937     return 0;
1938 }
1939 
update_result(RESULT & res)1940 int DB_VALIDATOR_ITEM_SET::update_result(RESULT& res) {
1941     char query[MAX_QUERY_LEN];
1942 
1943     sprintf(query,
1944         "update result set validate_state=%d, granted_credit=%.15e, "
1945         "server_state=%d, outcome=%d, opaque=%lf, runtime_outlier=%d "
1946         "where id=%lu",
1947         res.validate_state,
1948         res.granted_credit,
1949         res.server_state,
1950         res.outcome,
1951         res.opaque,
1952         res.runtime_outlier?1:0,
1953         res.id
1954     );
1955     int retval = db->do_query(query);
1956     if (db->affected_rows() != 1) return ERR_DB_NOT_FOUND;
1957     return retval;
1958 }
1959 
1960 
update_workunit(WORKUNIT & wu)1961 int DB_VALIDATOR_ITEM_SET::update_workunit(WORKUNIT& wu) {
1962     char query[MAX_QUERY_LEN];
1963 
1964     sprintf(query,
1965         "update workunit set need_validate=0, error_mask=%d, "
1966         "assimilate_state=%d, transition_time=%d, "
1967         "target_nresults=%d, "
1968         "canonical_resultid=%lu, canonical_credit=%.15e "
1969         "where id=%lu",
1970         wu.error_mask,
1971         wu.assimilate_state,
1972         wu.transition_time,
1973         wu.target_nresults,
1974         wu.canonical_resultid,
1975         wu.canonical_credit,
1976         wu.id
1977     );
1978     int retval = db->do_query(query);
1979     if (db->affected_rows() != 1) return ERR_DB_NOT_FOUND;
1980     return retval;
1981 }
1982 
parse(MYSQL_ROW & r)1983 void WORK_ITEM::parse(MYSQL_ROW& r) {
1984     int i=0;
1985     memset(this, 0, sizeof(WORK_ITEM));
1986     res_id = atol(r[i++]);
1987     res_priority = atoi(r[i++]);
1988     res_server_state = atoi(r[i++]);
1989     res_report_deadline = atof(r[i++]);
1990     wu.id = atol(r[i++]);
1991     wu.create_time = atoi(r[i++]);
1992     wu.appid = atol(r[i++]);
1993     strcpy2(wu.name, r[i++]);
1994     strcpy2(wu.xml_doc, r[i++]);
1995     wu.batch = atoi(r[i++]);
1996     wu.rsc_fpops_est = atof(r[i++]);
1997     wu.rsc_fpops_bound = atof(r[i++]);
1998     wu.rsc_memory_bound = atof(r[i++]);
1999     wu.rsc_disk_bound = atof(r[i++]);
2000     wu.need_validate = atoi(r[i++]);
2001     wu.canonical_resultid = atol(r[i++]);
2002     wu.canonical_credit = atof(r[i++]);
2003     wu.transition_time = atoi(r[i++]);
2004     wu.delay_bound = atoi(r[i++]);
2005     wu.error_mask = atoi(r[i++]);
2006     wu.file_delete_state = atoi(r[i++]);
2007     wu.assimilate_state = atoi(r[i++]);
2008     wu.hr_class = atoi(r[i++]);
2009     wu.opaque = atof(r[i++]);
2010     wu.min_quorum = atoi(r[i++]);
2011     wu.target_nresults = atoi(r[i++]);
2012     wu.max_error_results = atoi(r[i++]);
2013     wu.max_total_results = atoi(r[i++]);
2014     wu.max_success_results = atoi(r[i++]);
2015     strcpy2(wu.result_template_file, r[i++]);
2016     wu.priority = atoi(r[i++]);
2017     strcpy2(wu.mod_time, r[i++]);
2018     wu.rsc_bandwidth_bound = atof(r[i++]);
2019     wu.fileset_id = atol(r[i++]);
2020     wu.app_version_id = atol(r[i++]);
2021     wu.transitioner_flags = atoi(r[i++]);
2022     wu.size_class = atoi(r[i++]);
2023 }
2024 
enumerate(int limit,const char * select_clause,const char * order_clause)2025 int DB_WORK_ITEM::enumerate(
2026     int limit, const char* select_clause, const char* order_clause
2027 ) {
2028     char query[MAX_QUERY_LEN];
2029     int retval;
2030     MYSQL_ROW row;
2031     if (!cursor.active) {
2032         // use "r1" to refer to the result, since the feeder assumes that
2033         // (historical reasons)
2034         //
2035         sprintf(query,
2036             "select high_priority r1.id, r1.priority, r1.server_state, r1.report_deadline, workunit.* from result r1 force index(ind_res_st), workunit, app "
2037             " where r1.server_state=%d "
2038             " and r1.workunitid=workunit.id "
2039             " and workunit.appid=app.id "
2040             " and app.deprecated=0 "
2041             " and workunit.transitioner_flags=0 "
2042             " %s "
2043             " %s "
2044             "limit %d",
2045             RESULT_SERVER_STATE_UNSENT,
2046             select_clause,
2047             order_clause,
2048             limit
2049         );
2050         retval = db->do_query(query);
2051         if (retval) return mysql_errno(db->mysql);
2052         cursor.rp = mysql_store_result(db->mysql);
2053         if (!cursor.rp) return mysql_errno(db->mysql);
2054         cursor.active = true;
2055     }
2056     row = mysql_fetch_row(cursor.rp);
2057     if (!row) {
2058         mysql_free_result(cursor.rp);
2059         cursor.active = false;
2060         retval = mysql_errno(db->mysql);
2061         if (retval) return ERR_DB_CONN_LOST;
2062         return ERR_DB_NOT_FOUND;
2063     } else {
2064         parse(row);
2065     }
2066     return 0;
2067 }
2068 
enumerate_all(int limit,const char * select_clause)2069 int DB_WORK_ITEM::enumerate_all(
2070     int limit, const char* select_clause
2071 ) {
2072     char query[MAX_QUERY_LEN];
2073     int retval;
2074     MYSQL_ROW row;
2075     if (!cursor.active) {
2076         // use "r1" to refer to the result, since the feeder assumes that
2077         // (historical reasons)
2078         //
2079         sprintf(query,
2080             "select high_priority r1.id, r1.priority, r1.server_state, r1.report_deadline, workunit.* from result r1 force index(ind_res_st), workunit force index(primary), app"
2081             " where r1.server_state=%d and r1.workunitid=workunit.id and r1.id>%lu "
2082             " and workunit.appid=app.id and app.deprecated=0 "
2083             " and workunit.transitioner_flags=0 "
2084             " %s "
2085             "limit %d",
2086             RESULT_SERVER_STATE_UNSENT,
2087             start_id,
2088             select_clause,
2089             limit
2090         );
2091         retval = db->do_query(query);
2092         if (retval) return mysql_errno(db->mysql);
2093         cursor.rp = mysql_store_result(db->mysql);
2094         if (!cursor.rp) return mysql_errno(db->mysql);
2095 
2096         // if query gets no rows, start over in ID space
2097         //
2098         if (mysql_num_rows(cursor.rp) == 0) {
2099             mysql_free_result(cursor.rp);
2100             start_id = 0;
2101             return ERR_DB_NOT_FOUND;
2102         }
2103         cursor.active = true;
2104     }
2105     row = mysql_fetch_row(cursor.rp);
2106     if (!row) {
2107         mysql_free_result(cursor.rp);
2108         cursor.active = false;
2109         retval = mysql_errno(db->mysql);
2110         if (retval) return ERR_DB_CONN_LOST;
2111         return ERR_DB_NOT_FOUND;
2112     } else {
2113         parse(row);
2114         start_id = res_id;
2115     }
2116     return 0;
2117 }
2118 
2119 
parse(MYSQL_ROW & r)2120 void IN_PROGRESS_RESULT::parse(MYSQL_ROW& r) {
2121     int i=0;
2122     memset(this, 0, sizeof(IN_PROGRESS_RESULT));
2123     strcpy2(result_name,r[i++]);
2124     error_mask = atoi(r[i++]);
2125     assimilate_state = atoi(r[i++]);
2126     server_state = atoi(r[i++]);
2127     outcome = atoi(r[i++]);
2128 }
2129 
enumerate(DB_ID_TYPE hostid,const char * result_names)2130 int DB_IN_PROGRESS_RESULT::enumerate(DB_ID_TYPE hostid, const char* result_names) {
2131     char query[MAX_QUERY_LEN];
2132     int retval;
2133     MYSQL_ROW row;
2134     if (!cursor.active) {
2135         sprintf(query,
2136             "select high_priority result.name, workunit.error_mask, workunit.assimilate_state, result.server_state, result.outcome "
2137             " from result, workunit "
2138             " where result.hostid = %lu and workunit.id = result.workunitid "
2139             " and (result.server_state=%d or ( result.server_state = %d and result.outcome = %d ) ) "
2140             " and result.name in (%s) ",
2141             hostid,
2142             RESULT_SERVER_STATE_IN_PROGRESS,
2143             RESULT_SERVER_STATE_OVER,
2144             RESULT_OUTCOME_NO_REPLY,
2145             result_names
2146         );
2147         retval = db->do_query(query);
2148         if (retval) return mysql_errno(db->mysql);
2149         cursor.rp = mysql_store_result(db->mysql);
2150         if (!cursor.rp) return mysql_errno(db->mysql);
2151         cursor.active = true;
2152     }
2153     row = mysql_fetch_row(cursor.rp);
2154     if (!row) {
2155         mysql_free_result(cursor.rp);
2156         cursor.active = false;
2157         retval = mysql_errno(db->mysql);
2158         if (retval) return ERR_DB_CONN_LOST;
2159         return ERR_DB_NOT_FOUND;
2160     } else {
2161         parse(row);
2162     }
2163     return 0;
2164 }
2165 
2166 // The items that appear here must agree with those that appear in the
2167 // enumerate method just below!
2168 //
parse(MYSQL_ROW & r)2169 void SCHED_RESULT_ITEM::parse(MYSQL_ROW& r) {
2170     int i=0;
2171     clear();
2172     id = atol(r[i++]);
2173     strcpy2(name, r[i++]);
2174     workunitid = atol(r[i++]);
2175     appid = atol(r[i++]);
2176     server_state = atoi(r[i++]);
2177     hostid = atol(r[i++]);
2178     userid = atol(r[i++]);
2179     sent_time = atoi(r[i++]);
2180     received_time = atoi(r[i++]);
2181     validate_state = atoi(r[i++]);
2182     outcome = atoi(r[i++]);
2183     client_state = atoi(r[i++]);
2184     file_delete_state = atoi(r[i++]);
2185     app_version_id = atol(r[i++]);
2186 }
2187 
add_result(char * result_name)2188 int DB_SCHED_RESULT_ITEM_SET::add_result(char* result_name) {
2189     SCHED_RESULT_ITEM result;
2190     result.id = 0;
2191     strcpy2(result.queried_name, result_name);
2192     results.push_back(result);
2193     return 0;
2194 }
2195 
enumerate()2196 int DB_SCHED_RESULT_ITEM_SET::enumerate() {
2197     string query;
2198     int retval;
2199     unsigned int i;
2200     MYSQL_RES* rp;
2201     MYSQL_ROW row;
2202     SCHED_RESULT_ITEM ri;
2203 
2204 
2205     query =
2206         "SELECT "
2207         "   id, "
2208         "   name, "
2209         "   workunitid, "
2210         "   appid, "
2211         "   server_state, "
2212         "   hostid, "
2213         "   userid, "
2214         "   sent_time, "
2215         "   received_time, "
2216         "   validate_state, "
2217         "   outcome, "
2218         "   client_state, "
2219         "   file_delete_state, "
2220         "   app_version_id "
2221         "FROM "
2222         "   result "
2223         "WHERE "
2224         "   name IN ( "
2225     ;
2226 
2227     for (i=0; i<results.size(); i++) {
2228         if (i>0) query += ",";
2229         query += "'";
2230         query += results[i].queried_name;
2231         query += "'";
2232     }
2233     query += ")";
2234 
2235     retval = db->do_query(query.c_str());
2236     if (retval) return retval;
2237 
2238     // the following stores the entire result set in memory
2239     //
2240     rp = mysql_store_result(db->mysql);
2241     if (!rp) return mysql_errno(db->mysql);
2242 
2243     do {
2244         row = mysql_fetch_row(rp);
2245         if (!row) {
2246             mysql_free_result(rp);
2247         } else {
2248             ri.parse(row);
2249             for (i=0; i<results.size(); i++) {
2250                 if (!strcmp(results[i].queried_name, ri.name)) {
2251                     results[i] = ri;
2252                 }
2253             }
2254         }
2255     } while (row);
2256 
2257     return 0;
2258 }
2259 
lookup_result(char * result_name,SCHED_RESULT_ITEM ** rip)2260 int DB_SCHED_RESULT_ITEM_SET::lookup_result(char* result_name, SCHED_RESULT_ITEM** rip) {
2261     unsigned int i;
2262     for (i=0; i<results.size(); i++) {
2263         if (!strcmp(results[i].name, result_name)) {
2264             *rip = &results[i];
2265             return 0;
2266         }
2267     }
2268     return -1;
2269 }
2270 
update_result(SCHED_RESULT_ITEM & ri)2271 int DB_SCHED_RESULT_ITEM_SET::update_result(SCHED_RESULT_ITEM& ri) {
2272     char query[MAX_QUERY_LEN];
2273     int retval;
2274 
2275     ESCAPE(ri.xml_doc_out);
2276     ESCAPE(ri.stderr_out);
2277     sprintf(query,
2278         "UPDATE result SET "
2279         "    hostid=%lu, "
2280         "    received_time=%d, "
2281         "    client_state=%d, "
2282         "    cpu_time=%.15e, "
2283         "    exit_status=%d, "
2284         "    app_version_num=%d, "
2285         "    server_state=%d, "
2286         "    outcome=%d, "
2287         "    stderr_out='%s', "
2288         "    xml_doc_out='%s', "
2289         "    validate_state=%d, "
2290         "    teamid=%lu, "
2291         "    elapsed_time=%.15e, "
2292         "    peak_working_set_size=%.0f, "
2293         "    peak_swap_size=%.0f, "
2294         "    peak_disk_usage=%.0f "
2295         "WHERE "
2296         "    id=%lu",
2297         ri.hostid,
2298         ri.received_time,
2299         ri.client_state,
2300         ri.cpu_time,
2301         ri.exit_status,
2302         ri.app_version_num,
2303         ri.server_state,
2304         ri.outcome,
2305         ri.stderr_out,
2306         ri.xml_doc_out,
2307         ri.validate_state,
2308         ri.teamid,
2309         ri.elapsed_time,
2310         ri.peak_working_set_size,
2311         ri.peak_swap_size,
2312         ri.peak_disk_usage,
2313         ri.id
2314     );
2315     retval = db->do_query(query);
2316     UNESCAPE(ri.xml_doc_out);
2317     UNESCAPE(ri.stderr_out);
2318     if (db->affected_rows() != 1) return ERR_DB_NOT_FOUND;
2319     return retval;
2320 }
2321 
2322 // set transition times of workunits -
2323 // but only those corresponding to updated results
2324 // (i.e. those that passed "sanity checks")
2325 //
update_workunits()2326 int DB_SCHED_RESULT_ITEM_SET::update_workunits() {
2327     char query[MAX_QUERY_LEN], buf[256];
2328     unsigned int i;
2329     bool first= true;
2330 
2331     sprintf(query,
2332         "UPDATE workunit SET transition_time=%d WHERE id in (",
2333         (int)time(0)
2334     );
2335     for (i=0; i<results.size(); i++) {
2336         if (results[i].id == 0) continue;
2337             // skip non-updated results
2338         if (!first) strcat(query, ",");
2339         first = false;
2340         sprintf(buf, "%lu", results[i].workunitid);
2341         strcat(query, buf);
2342     }
2343     strcat(query, ")");
2344     if (first) {
2345         return 0;
2346     } else {
2347         return db->do_query(query);
2348     }
2349 }
2350 
db_print(char * buf)2351 void DB_FILE::db_print(char* buf){
2352     snprintf(buf, MAX_QUERY_LEN,
2353         "name='%s', md5sum='%s', size=%.15e",
2354         name, md5sum, size
2355     );
2356 }
2357 
db_parse(MYSQL_ROW & r)2358 void DB_FILE::db_parse(MYSQL_ROW &r) {
2359     int i=0;
2360     clear();
2361     id = atol(r[i++]);
2362     strcpy2(name, r[i++]);
2363     strcpy2(md5sum, r[i++]);
2364     size = atof(r[i++]);
2365 }
2366 
db_print(char * buf)2367 void DB_FILESET::db_print(char* buf){
2368     snprintf(buf, MAX_QUERY_LEN, "name='%s'", name);
2369 }
2370 
db_parse(MYSQL_ROW & r)2371 void DB_FILESET::db_parse(MYSQL_ROW &r) {
2372     int i=0;
2373     clear();
2374     id = atol(r[i++]);
2375     strcpy2(name, r[i++]);
2376 }
2377 
select_by_name(const char * _name)2378 int DB_FILESET::select_by_name(const char* _name) {
2379     char where_clause[MAX_QUERY_LEN] = {0};
2380 
2381     // construct where clause and select single record
2382     snprintf(where_clause, MAX_QUERY_LEN, "WHERE name = '%s'", _name);
2383     return lookup(where_clause);
2384 }
2385 
db_print(char * buf)2386 void DB_FILESET_FILE::db_print(char* buf){
2387     snprintf(buf, MAX_QUERY_LEN,
2388         "fileset_id=%lu, file_id=%lu",
2389         fileset_id, file_id
2390     );
2391 }
2392 
db_parse(MYSQL_ROW & r)2393 void DB_FILESET_FILE::db_parse(MYSQL_ROW &r) {
2394     int i=0;
2395     clear();
2396     fileset_id = atol(r[i++]);
2397     file_id = atol(r[i++]);
2398 }
2399 
db_print(char * buf)2400 void DB_SCHED_TRIGGER::db_print(char* buf){
2401     snprintf(buf, MAX_QUERY_LEN,
2402         "fileset_id=%lu, need_work=%d, work_available=%d, no_work_available=%d, working_set_removal=%d",
2403         fileset_id, need_work?1:0, work_available?1:0, no_work_available?1:0, working_set_removal?1:0
2404     );
2405 }
2406 
db_parse(MYSQL_ROW & r)2407 void DB_SCHED_TRIGGER::db_parse(MYSQL_ROW &r) {
2408     int i=0;
2409     clear();
2410     id = atol(r[i++]);
2411     fileset_id = atol(r[i++]);
2412     need_work = atoi(r[i++]);
2413     work_available = atoi(r[i++]);
2414     no_work_available = atoi(r[i++]);
2415     working_set_removal = atoi(r[i++]);
2416 }
2417 
select_unique_by_fileset_name(const char * fileset_name)2418 int DB_SCHED_TRIGGER::select_unique_by_fileset_name(const char* fileset_name) {
2419     char query[MAX_QUERY_LEN];
2420     int retval;
2421     int nrows = 0;
2422     MYSQL_RES* recordset;
2423     MYSQL_ROW row;
2424 
2425     //if (!cursor.active) {
2426         // prepare statement
2427         snprintf(query, MAX_QUERY_LEN,
2428             "SELECT"
2429             "  t.id,"
2430             "  t.fileset_id,"
2431             "  t.need_work,"
2432             "  t.work_available,"
2433             "  t.no_work_available,"
2434             "  t.working_set_removal "
2435             "FROM"
2436             "  fileset fs INNER JOIN sched_trigger t ON fs.id = t.fileset_id "
2437             "WHERE"
2438             "  fs.name = '%s'",
2439             fileset_name
2440         );
2441 
2442         retval = db->do_query(query);
2443 
2444         if (retval) return mysql_errno(db->mysql);
2445 
2446         recordset = mysql_store_result(db->mysql);
2447         if (!recordset) return mysql_errno(db->mysql);
2448     //}
2449 
2450     // determine number of records, fetch first
2451     nrows = mysql_num_rows(recordset);
2452     row = mysql_fetch_row(recordset);
2453 
2454     if (!row || nrows != 1) {
2455         // something bad happened
2456         if (!row) {
2457             // no row returned, due to an error?
2458             retval = mysql_errno(db->mysql);
2459             mysql_free_result(recordset);
2460 
2461             // yes, probably lost DB connection
2462             if (retval) return ERR_DB_CONN_LOST;
2463 
2464             // no, just no record available
2465             return ERR_DB_NOT_FOUND;
2466         }
2467         else {
2468             // we got more records than expected
2469             mysql_free_result(recordset);
2470             return ERR_DB_NOT_UNIQUE;
2471         }
2472     } else {
2473         // all fine, parse single record
2474         db_parse(row);
2475         mysql_free_result(recordset);
2476     }
2477     return 0;
2478 }
2479 
update_single_state(const DB_SCHED_TRIGGER::STATE state,const bool value)2480 int DB_SCHED_TRIGGER::update_single_state(const DB_SCHED_TRIGGER::STATE state, const bool value) {
2481     char column_clause[MAX_QUERY_LEN] = {0};
2482     int retval = 0;
2483 
2484     switch(state) {
2485     case DB_SCHED_TRIGGER::state_need_work:
2486         snprintf(column_clause, MAX_QUERY_LEN, "need_work = %d", value?1:0);
2487         need_work = value;
2488         break;
2489     case DB_SCHED_TRIGGER::state_work_available:
2490         snprintf(column_clause, MAX_QUERY_LEN, "work_available = %d", value?1:0);
2491         work_available = value;
2492         break;
2493     case DB_SCHED_TRIGGER::state_no_work_available:
2494         snprintf(column_clause, MAX_QUERY_LEN, "no_work_available = %d", value?1:0);
2495         no_work_available = value;
2496         break;
2497     case DB_SCHED_TRIGGER::state_working_set_removal:
2498         snprintf(column_clause, MAX_QUERY_LEN, "working_set_removal = %d", value?1:0);
2499         working_set_removal = value;
2500         break;
2501     default:
2502         // unknown state
2503         return -1;
2504     }
2505 
2506     // run actual update on current trigger (retrieved earlier)
2507     retval = update_field(column_clause, NULL);
2508 
2509     if (retval) return retval;
2510     return 0;
2511 }
2512 
db_parse(MYSQL_ROW & r)2513 void DB_FILESET_SCHED_TRIGGER_ITEM::db_parse(MYSQL_ROW &r) {
2514     int i=0;
2515     clear();
2516     fileset.id = atol(r[i++]);
2517     strcpy2(fileset.name, r[i++]);
2518     trigger.id = atol(r[i++]);
2519     trigger.fileset_id = atol(r[i++]);
2520     trigger.need_work = atoi(r[i++]);
2521     trigger.work_available = atoi(r[i++]);
2522     trigger.no_work_available = atoi(r[i++]);
2523     trigger.working_set_removal = atoi(r[i++]);
2524 }
2525 
select_by_name_state(const char * fileset_name=NULL,const bool use_regexp=false,const DB_SCHED_TRIGGER::STATE state=DB_SCHED_TRIGGER::none,const bool state_value=true)2526 int DB_FILESET_SCHED_TRIGGER_ITEM_SET::select_by_name_state(
2527     const char* fileset_name = NULL,
2528     const bool use_regexp = false,
2529     const DB_SCHED_TRIGGER::STATE state = DB_SCHED_TRIGGER::none,
2530     const bool state_value = true
2531 ) {
2532     char where_clause[MAX_QUERY_LEN] = {0};
2533     char query[MAX_QUERY_LEN] = {0};
2534     int retval = 0;
2535     int count = 0;
2536     MYSQL_RES* recordset;
2537     MYSQL_ROW row;
2538     DB_FILESET_SCHED_TRIGGER_ITEM fileset_trigger;
2539 
2540     // prepare requested compare mode
2541     const char* comparator = use_regexp ? "REGEXP" : "=";
2542 
2543     // prepare optional state filter
2544     char state_filter[MAX_QUERY_LEN] = {0};
2545     switch(state) {
2546     case DB_SCHED_TRIGGER::state_need_work:
2547         snprintf(state_filter, MAX_QUERY_LEN, "need_work = %d", state_value?1:0);
2548         break;
2549     case DB_SCHED_TRIGGER::state_work_available:
2550         snprintf(state_filter, MAX_QUERY_LEN, "work_available = %d", state_value?1:0);
2551         break;
2552     case DB_SCHED_TRIGGER::state_no_work_available:
2553         snprintf(state_filter, MAX_QUERY_LEN, "no_work_available = %d", state_value?1:0);
2554         break;
2555     case DB_SCHED_TRIGGER::state_working_set_removal:
2556         snprintf(state_filter, MAX_QUERY_LEN, "working_set_removal = %d", state_value?1:0);
2557         break;
2558     default:
2559         // none or unknown state (keep empty filter)
2560         break;
2561     }
2562 
2563     // prepare WHERE clause
2564     if(fileset_name && !state) {
2565         snprintf(where_clause, MAX_QUERY_LEN, "WHERE fs.name %s '%s'", comparator, fileset_name);
2566     } else if(!fileset_name && state) {
2567         snprintf(where_clause, MAX_QUERY_LEN, "WHERE %s", state_filter);
2568     } else if(fileset_name && state) {
2569         snprintf(where_clause, MAX_QUERY_LEN, "WHERE fs.name %s '%s' AND %s", comparator, fileset_name, state_filter);
2570     }
2571 
2572     // prepare final statement
2573     snprintf(query, MAX_QUERY_LEN,
2574         "SELECT"
2575         "  fs.id,"
2576         "  fs.name,"
2577         "  t.id,"
2578         "  t.fileset_id,"
2579         "  t.need_work,"
2580         "  t.work_available,"
2581         "  t.no_work_available,"
2582         "  t.working_set_removal "
2583         "FROM"
2584         "  fileset fs INNER JOIN sched_trigger t ON fs.id = t.fileset_id "
2585         "%s",
2586         where_clause
2587     );
2588 
2589     retval = db->do_query(query);
2590     if (retval) return retval;
2591 
2592     recordset = mysql_store_result(db->mysql);
2593     if (!recordset) return mysql_errno(db->mysql);
2594 
2595     // check if we got at least one record
2596     count = mysql_num_rows(recordset);
2597     if(count == 0) {
2598         mysql_free_result(recordset);
2599         return ERR_DB_NOT_FOUND;
2600     }
2601 
2602     // all fine, iterate over recordset
2603     do {
2604         row = mysql_fetch_row(recordset);
2605         if (!row) {
2606             // clean up
2607             mysql_free_result(recordset);
2608 
2609             // no row returned, due to an error?
2610             retval = mysql_errno(db->mysql);
2611             // yes, probably lost DB connection
2612             if (retval) return ERR_DB_CONN_LOST;
2613         } else {
2614             // parse record, add to vector
2615             fileset_trigger.db_parse(row);
2616             items.push_back(fileset_trigger);
2617         }
2618     } while (row);
2619 
2620     return 0;
2621 }
2622 
contains_trigger(const char * fileset_name)2623 int DB_FILESET_SCHED_TRIGGER_ITEM_SET::contains_trigger(
2624     const char* fileset_name
2625 ) {
2626     // iterate over item vector
2627     for (unsigned int i=0; i<items.size(); ++i) {
2628         if (strcmp(items[i].fileset.name, fileset_name) == 0) {
2629             // return 1-indexed position for boolean tests
2630             return i+1;
2631         }
2632     }
2633     return 0;
2634 }
2635 
db_print(char * buf)2636 void DB_VDA_FILE::db_print(char* buf){
2637     sprintf(buf,
2638         "create_time=%f, "
2639         "dir='%s', "
2640         "file_name='%s', "
2641         "size=%f, "
2642         "chunk_size=%f, "
2643         "need_update=%d, "
2644         "initialized=%d, "
2645         "retrieving=%d, "
2646         "retrieved=%d",
2647         create_time,
2648         dir,
2649         file_name,
2650         size,
2651         chunk_size,
2652         need_update?1:0,
2653         initialized?1:0,
2654         retrieving?1:0,
2655         retrieved?1:0
2656     );
2657 }
2658 
db_parse(MYSQL_ROW & r)2659 void DB_VDA_FILE::db_parse(MYSQL_ROW &r) {
2660     int i=0;
2661     clear();
2662     id = atol(r[i++]);
2663     create_time = atof(r[i++]);
2664     strcpy2(dir, r[i++]);
2665     strcpy2(file_name, r[i++]);
2666     size = atof(r[i++]);
2667     chunk_size = atof(r[i++]);
2668     need_update = (atoi(r[i++]) != 0);
2669     initialized = (atoi(r[i++]) != 0);
2670     retrieving = (atoi(r[i++]) != 0);
2671     retrieved = (atoi(r[i++]) != 0);
2672 }
2673 
db_print(char * buf)2674 void DB_VDA_CHUNK_HOST::db_print(char* buf) {
2675     sprintf(buf,
2676         "create_time=%f, "
2677         "vda_file_id=%lu, "
2678         "host_id=%lu, "
2679         "physical_file_name='%s', "
2680         "present_on_host=%d, "
2681         "transfer_in_progress=%d, "
2682         "transfer_wait=%d, "
2683         "transfer_request_time=%f, "
2684         "transfer_send_time=%f ",
2685         create_time,
2686         vda_file_id,
2687         host_id,
2688         physical_file_name,
2689         present_on_host,
2690         transfer_in_progress,
2691         transfer_wait,
2692         transfer_request_time,
2693         transfer_send_time
2694     );
2695 }
2696 
db_parse(MYSQL_ROW & r)2697 void DB_VDA_CHUNK_HOST::db_parse(MYSQL_ROW &r) {
2698     int i=0;
2699     clear();
2700     create_time = atof(r[i++]);
2701     vda_file_id = atol(r[i++]);
2702     host_id = atol(r[i++]);
2703     strcpy2(physical_file_name, r[i++]);
2704     present_on_host = (atoi(r[i++]) != 0);
2705     transfer_in_progress = (atoi(r[i++]) != 0);
2706     transfer_wait = (atoi(r[i++]) != 0);
2707     transfer_request_time = atof(r[i++]);
2708     transfer_send_time = atof(r[i++]);
2709 }
2710 
db_parse(MYSQL_ROW & r)2711 void DB_BADGE::db_parse(MYSQL_ROW &r) {
2712     int i=0;
2713     clear();
2714     id = atol(r[i++]);
2715     create_time = atof(r[i++]);
2716     type = atoi(r[i++]);
2717     strcpy2(name, r[i++]);
2718     strcpy2(title, r[i++]);
2719     strcpy2(description, r[i++]);
2720     strcpy2(image_url, r[i++]);
2721     strcpy2(level, r[i++]);
2722     strcpy2(tags, r[i++]);
2723     strcpy2(sql_rule, r[i++]);
2724 }
2725 
db_parse(MYSQL_ROW & r)2726 void DB_BADGE_USER::db_parse(MYSQL_ROW &r) {
2727     int i=0;
2728     clear();
2729     badge_id = atol(r[i++]);
2730     user_id = atol(r[i++]);
2731     create_time = atof(r[i++]);
2732     reassign_time = atof(r[i++]);
2733 }
2734 
db_parse(MYSQL_ROW & r)2735 void DB_BADGE_TEAM::db_parse(MYSQL_ROW &r) {
2736     int i=0;
2737     clear();
2738     badge_id = atol(r[i++]);
2739     team_id = atol(r[i++]);
2740     create_time = atof(r[i++]);
2741     reassign_time = atof(r[i++]);
2742 }
2743 
db_print(char * buf)2744 void DB_CREDIT_USER::db_print(char* buf) {
2745     sprintf(buf,
2746         "userid=%lu, "
2747         "appid=%lu, "
2748         "njobs=%d, "
2749         "total=%.15e, "
2750         "expavg=%.15e, "
2751         "expavg_time=%.15e, "
2752         "credit_type=%d ",
2753         userid,
2754         appid,
2755         njobs,
2756         total,
2757         expavg,
2758         expavg_time,
2759         credit_type
2760     );
2761 }
2762 
db_parse(MYSQL_ROW & r)2763 void DB_CREDIT_USER::db_parse(MYSQL_ROW &r) {
2764     int i=0;
2765     clear();
2766     userid = atol(r[i++]);
2767     appid = atol(r[i++]);
2768     njobs = atoi(r[i++]);
2769     total = atof(r[i++]);
2770     expavg = atof(r[i++]);
2771     expavg_time = atof(r[i++]);
2772     credit_type = atoi(r[i++]);
2773 }
2774 
db_print(char * buf)2775 void DB_CREDIT_TEAM::db_print(char* buf) {
2776     sprintf(buf,
2777         "teamid=%lu, "
2778         "appid=%lu, "
2779         "njobs=%d, "
2780         "total=%.15e, "
2781         "expavg=%.15e, "
2782         "expavg_time=%.15e, "
2783         "credit_type=%d ",
2784         teamid,
2785         appid,
2786         njobs,
2787         total,
2788         expavg,
2789         expavg_time,
2790         credit_type
2791     );
2792 }
2793 
db_parse(MYSQL_ROW & r)2794 void DB_CREDIT_TEAM::db_parse(MYSQL_ROW &r) {
2795     int i=0;
2796     clear();
2797     teamid = atol(r[i++]);
2798     appid = atol(r[i++]);
2799     njobs = atoi(r[i++]);
2800     total = atof(r[i++]);
2801     expavg = atof(r[i++]);
2802     expavg_time = atof(r[i++]);
2803     credit_type = atoi(r[i++]);
2804 }
2805 
2806 const char *BOINC_RCSID_ac374386c8 = "$Id$";
2807