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