my_judged.cc 的初稿

#include <time.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>  
#include <stdlib.h>
#include <unistd.h>   /* fork(), read函数、write函数和getpid函数*/
#include <syslog.h>   /*int syslog(int priority, string message); 本函数将 message 字符串写到系统纪录中 */
#include <errno.h>    // 出错码
#include <fcntl.h>    /* fcntl.h定义了很多宏和open */
#include <stdarg.h>   /* 让函数能够接收可变参数 */
#include <mysql/mysql.h>

#include <sys/wait.h>  // 进程控制
#include <sys/stat.h>  // 文件状态  2-> waitpid().
#include <signal.h>    // 信号

#define BUFFER_SIZE 1024
#define LOCKFILE "/var/run/judged.pid"  // 文件路径宏定义  /var/run/judged.pid
#define LOCKMODE (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH) // 所有者可以 r 和 w, g 和 o 可以 r 。
#define STD_MB 1048576

#define OJ_WT0 0 // Pending // 正等待...
#define OJ_WT1 1 // Pending_Rejudging
#define OJ_CI 2  // Compiling
#define OJ_RI 3  // Running_Judging
#define OJ_AC 4  // Accepted
#define OJ_PE 5  // Presentation Error
#define OJ_WA 6  // Wrong Answer
#define OJ_TL 7  // Time Limit Exceeded
#define OJ_ML 8  // Memory Limit Exceeded
#define OJ_OL 9  // Output Limit Exceeded
#define OJ_RE 10 // Runtime Error
#define OJ_CE 11 // Compilation Error
#define OJ_CO 12 // Compile_OK

static char host_name[BUFFER_SIZE];
static char user_name[BUFFER_SIZE];
static char password [BUFFER_SIZE];
static char db_name  [BUFFER_SIZE];
static char oj_home  [BUFFER_SIZE];
static char oj_lang_set[BUFFER_SIZE];  // 
static int port_number;
static int max_running; // 可以运行的 judge_client 的数量上限。
static int sleep_time;  // 数据库轮询间隔
static int sleep_tmp;
static int oj_tot; // 老式并发处理中总的 judged 数量
static int oj_mod; // 老式并发处理中,本 judged 负责处理 solution_id 按照 TOTAL 取模后余数为几的任务。

static bool STOP = false;

static MYSQL *conn;   /************* 数据库 类型 *****************/
static MYSQL_RES *res;
static MYSQL_ROW row;

static char query[BUFFER_SIZE];

void call_for_exit(int s) {
	STOP = true;
	printf("Stopping judged...\n");
}
void write_log(const char *fmt, ...) {
	va_list ap;
	char buffer[4096];
//	time_t          t = time(NULL);
//	int             l;
	sprintf(buffer,"%s/log/client.log",oj_home);
	FILE *fp = fopen(buffer, "a+");
	if (fp == NULL){
		 fprintf(stderr, "openfile error!\n");
		 system("pwd");
	} va_start(ap, fmt);
	vsprintf(buffer, fmt, ap);
	fprintf(fp,"%s\n",buffer);
	va_end(ap);
	fclose(fp);
}

int after_equal(char * c){
	int i=0;
	for(; c[i] != '\0' && c[i] != '='; i++);
	return ++i;
}
void trim(char * c){
    char buf[BUFFER_SIZE];
    char * start,*end;
    strcpy(buf,c);
    start=buf;
    while(isspace(*start)) start++;
    end=start;
    while(!isspace(*end)) end++;
    *end='\0';
    strcpy(c,start);
}
bool read_buf(char * buf,const char * key,char * value){
   if (strncmp(buf, key, strlen(key)) == 0) {
		strcpy(value, buf + after_equal(buf));
		trim(value);	
		return 1;
   }
   return 0;
}
void read_int(char * buf,const char * key,int * value){
	char buf2[BUFFER_SIZE];
	if (read_buf(buf, key, buf2))
		sscanf(buf2, "%d", value);
}
// read the configue file
void init_mysql_conf() {
	FILE *fp = NULL; // 文件指针类型 fp
	char buf[BUFFER_SIZE];
	host_name[0] = 0;
	user_name[0] = 0;
	password[0] = 0;
	db_name[0] = 0;
	port_number = 3306;
	max_running = 3; // 最多允许 3 个 judge_client 同时存在。
	sleep_time = 3; 
	oj_tot = 1;  // 老式并发处理中总的 judged 数量  
	oj_mod = 0;  // 老式并发处理中,本 judged 负责处理 solution_id 按照 TOTAL 取模后余数为几的任务。
	strcpy(oj_lang_set, "0, 1");
	fp = fopen("./etc/judge.conf", "r");
	if(fp != NULL){
		while(fgets(buf, BUFFER_SIZE - 1, fp)) {
			read_buf(buf, "OJ_HOST_NAME", host_name);	
			read_buf(buf, "OJ_USER_NAME", user_name);
			read_buf(buf, "OJ_PASSWORD", password);
			read_buf(buf, "OJ_DB_NAME", db_name);
			read_int(buf , "OJ_PORT_NUMBER", &port_number);
			read_int(buf, "OJ_RUNNING", &max_running);
			read_int(buf, "OJ_SLEEP_TIME", &sleep_time);
			read_int(buf , "OJ_TOTAL", &oj_tot);
			read_int(buf,"OJ_MOD",&oj_mod);
			read_buf(buf,"OJ_LANG_SET", oj_lang_set);
		}
		sprintf(query,"SELECT solution_id FROM solution WHERE language in (%s) and result<2 and MOD(solution_id,%d)=%d ORDER BY result ASC,solution_id ASC limit %d", oj_lang_set, oj_tot, oj_mod, max_running*2);
		sleep_tmp = sleep_time;
	//	fclose(fp);
    }
}
void run_client(int runid, int clientid){
    char buf[BUFFER_SIZE],runidstr[BUFFER_SIZE];
    struct rlimit LIM;
	LIM.rlim_max=800;
	LIM.rlim_cur=800;
	setrlimit(RLIMIT_CPU,&LIM);

	LIM.rlim_max=80*STD_MB;
	LIM.rlim_cur=80*STD_MB;
	setrlimit(RLIMIT_FSIZE,&LIM);

	LIM.rlim_max=STD_MB<<11;
	LIM.rlim_cur=STD_MB<<11;
	setrlimit(RLIMIT_AS,&LIM);
		
    LIM.rlim_cur=LIM.rlim_max=200;
    setrlimit(RLIMIT_NPROC, &LIM);
	//buf[0]=clientid+'0'; buf[1]=0;
	sprintf(runidstr, "%d", runid);
	sprintf(buf, "%d", clientid);
	execl("/usr/bin/judge_client", "/usr/bin/judge_client", runidstr, buf, oj_home, (char *)NULL);
}
int executesql(const char * sql) {
	if (mysql_real_query(conn, sql, strlen(sql))) { // 成功,函数返回零
		sleep(20);
		conn = NULL;
		return 1;
	} else
		return 0;
}
int init_mysql(){
    if(conn == NULL){
		conn = mysql_init(NULL);		// init the database connection
		/* connect the database */
		const char timeout = 30;
		mysql_options(conn, MYSQL_OPT_CONNECT_TIMEOUT, &timeout);

		if(!mysql_real_connect(conn, host_name, user_name, password, db_name, port_number, 0, 0)) {
			sleep(20);
			return 1; // 连接失败,mysql_real_connect 返回为 0.
		}
	}
	if (executesql("set names utf8"))
        return 1; // 执行失败
	return 0;
}
int  _get_jobs_mysql(int * jobs) {
	if (mysql_real_query(conn, query, strlen(query))) { // 成功返回 0, 读取未判的那些 solution_id 们。
		sleep(20); // 不存在 pending 中的 solution_id , 进程挂起 20 秒。
        return 0;
    }
    res = mysql_store_result(conn);
    int i = 0;
    int ret = 0;
    while((row = mysql_fetch_row(res)) != NULL) {
        jobs[i++] = atoi(row[0]); 
    }
    ret = i;
    while(i <= max_running*2) jobs[i++] = 0;
    return ret;
}
int get_jobs(int * jobs) {
	return _get_jobs_mysql(jobs);
}
bool _check_out_mysql(int solution_id, int result) { // workcnt < max_running && check_out(runid, OJ_CI)
	char sql[BUFFER_SIZE];
	sprintf(sql, "UPDATE solution SET result=%d,time=0,memory=0,judgetime=NOW() WHERE solution_id=%d and result<2 LIMIT 1"
			,result, solution_id);
	if (mysql_real_query(conn, sql, strlen(sql))) {
		syslog(LOG_ERR | LOG_DAEMON, "%s",mysql_error(conn));
		return false;
	} else {
		if(mysql_affected_rows(conn) > 0ul)
			return true;
		else
			return false;
	}
}
bool check_out(int solution_id, int result) {
	return _check_out_mysql(solution_id, result);
}
int work() {
	static  int retcnt = 0;
    int i = 0;
    static pid_t ID[100];  // 声明 100 大小的pid数组。
    static int workcnt = 0;
    int runid = 0;
    int jobs[max_running*2+1];  // max_running 是启动 judge_client 的上限
    pid_t tmp_pid = 0;
        /* get the database info */
    if(!get_jobs(jobs)) retcnt = 0; //  检索出的 solution_id 们,全都存在 jobs[] 中。retcnt 为 pending的solution_id的数量。
        /* exec the submit */
	for (int j = 0; jobs[j] > 0; j++) {
		runid = jobs[j];
        if (workcnt >= max_running) {    // if no more client can running
			tmp_pid = waitpid(-1, NULL, 0);     // wait 4 one child exit, pid=-1时,等待任何一个子进程退出,没有任何限制,此时waitpid和wait的作用一模一样
            workcnt--; retcnt++; // waitpid 返回收集到的子进程的进程ID, retcnt++, 这是hp?
            for (i = 0; i < max_running; i++)     // get the client id
				if (ID[i] == tmp_pid) break; // got the client id
            ID[i] = 0;
        } else {                                                  // have free client
			for (i = 0; i < max_running; i++)     // find the client id
				if (ID[i] == 0) break;    // got the client id
        }
        if(workcnt < max_running && check_out(runid, OJ_CI)) { // 要判题了,将result置为 OJ_CI
			workcnt++;                                        // client 增加一个。
            ID[i] = fork();                                   // start to fork
            if (ID[i] == 0) {
                run_client(runid, i);    // if the process is the son, run it,儿子你去判题吧,父亲继续运行。
                exit(0);
            }
        } else ID[i] = 0;
    }
    //下面回收运行完的进程号
    while ( (tmp_pid = waitpid(-1, NULL, WNOHANG) ) > 0) { // 如果使用了WNOHANG(wait no hung)参数调用waitpid,即使没有子进程退出,它也会立即返回
		workcnt--; retcnt++;   // 可能是立即返回,子进程没有主动退出的,也会立即终止一个子进程。
		for (i = 0; i < max_running; i++)     // get the client id
			if (ID[i] == tmp_pid) break;      // got the client id
        ID[i] = 0;
        printf("tmp_pid = %d\n", tmp_pid);
    }
	mysql_free_result(res);                         // free the memory
    executesql("commit");
    //free(ID);
    //free(jobs);
    return retcnt;
}
int lockfile(int fd) {
	struct flock fl;
	fl.l_type = F_WRLCK; // 独占性写锁定
	fl.l_start = 0;
	fl.l_whence = SEEK_SET; // SEEK_SET 文件头
	fl.l_len = 0;
	return (fcntl(fd, F_SETLK, &fl)); // F_SETLK 设置文件锁定的状态, 如果无法锁定返回 -1.
}
int already_running(){
	int fd;
	char buf[16];
	fd = open(LOCKFILE, O_RDWR|O_CREAT, LOCKMODE); // "/var/run/judged.pid" (S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)Permits the file's owner to read it.
	if (fd < 0){
		syslog(LOG_ERR|LOG_DAEMON, "can't open %s: %s", LOCKFILE, strerror(errno));
		exit(1);
	}
	if(lockfile(fd) < 0){      
		if (errno == EACCES || errno == EAGAIN){
			close(fd);
			return 1;
		}
		syslog(LOG_ERR|LOG_DAEMON, "can't lock %s: %s", LOCKFILE, strerror(errno));
		exit(1);
	}
	ftruncate(fd, 0); // 以写模式打开的文件,就理解为清空文件吧!先!
	sprintf(buf, "%d", getpid()); // getpid() 返回当前进程标识,将当前进程标识写入到 /var/run/judged.pid
	write(fd, buf, strlen(buf)+1);
	return (0);
}
int daemon_init(void) {
	pid_t pid;
	if((pid = fork()) < 0) return(-1);
	else if(pid != 0) exit(0);  /* parent exit */
	/* child continues */
	setsid(); /* become session leader */
	chdir(oj_home);  /* change working directory */
	umask(0);        /* clear file mode creation mask */
	close(0); /* close stdin */  // 切后台关闭这三个干嘛呀!
	close(1); /* close stdout */
	close(2); /* close stderr */
	return(0); 
}
int main(int argc, char** argv){
	strcpy(oj_home, "/home/judge");
	chdir(oj_home);

	daemon_init(); // 切后台
	if (strcmp(oj_home, "/home/judge") == 0 && already_running() ){
		syslog(LOG_ERR|LOG_DAEMON, "This daemon program is already running!\n"); // err, daemon
		return 1;  // syslogd守护进程用于解决守护进程的日志记录问题,openlog、syslog和closelog,日志信息会写入syslog.conf文件指定的位置
	}
	init_mysql_conf();	// set the database info
	signal(SIGQUIT, call_for_exit); // 输入Quit Key的时候(CTRL+\)发送给所有Foreground Group的进程
	signal(SIGKILL, call_for_exit); // 无法处理和忽略。中止某个进程
	signal(SIGTERM, call_for_exit); // 请求中止进程,kill命令缺省发送
	int j = 1;
	while (!STOP){			// start to run
	    while( j && (!init_mysql()) ){        
			    j = work();		
		}
		sleep(sleep_time); // judged 通过轮询数据库发现新任务,轮询间隔的休息时间,单位秒, 对应流程图。
		j = 1;
	}
	return 0;
}
all: my_judged2.cc
	g++ -Wall -c -I/usr/local/mysql/include/mysql -I/usr/include/mysql  my_judged2.cc
	g++ -Wall -o my_judged2 my_judged2.o -L/usr/local/mysql/lib/mysql -L/usr/lib/mysql  -lmysqlclient
// Special thanks to teacher Zhang for helping me.
马丁路德金的"I have a dream"节选存放在"freedom.txt"中: I have a dream that one day this nation will rise up, live up to the true meaning of its creed: “We hold these truths to be self-evident; that all men are created equal.” I have a dream that one day on the red hills of Georgia the sons of former slaves and the sons of former slave-owners will be able to sit down together at the table of br otherhood. I have a dream that one day even the state of Mississippi, a state sweltering with th e heat of injustice, sweltering with the heat of oppression, will be transformed into an oasis of freedom and justice. I have a dream that my four children will one day live in a nation where they will no t be judged by the color if their skin but by the content of their character. I have a dream today. I have a dream that one day down in Alabama with its governor having his lips drippin g with the words of interposition and nullification, one day right down in Alabama li ttle black boys and black girls will be able to join hands with little white boys and white girls as sisters and brothers. I have a dream today. I have a dream that one day every valley shall be exalted, every hill and mountain sh all be made low, the rough places will be made plain, and the crooked places will be made straight, and the glory of the Lord shall be revealed, and all flesh shall see i t together. 编程实现词汇表,计算每一个单词出现的次数,大小写不区分,输出到"dic.txt" 文件保存。
06-01
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值