mysql 쿼리를 처리하는 다중 접속 서버에서 ...

jiheony의 이미지

코드가 좀 깁니다. 그래도 급한 김에 올려보는데요..
테스트를 해봐야하는데 여러가지 문제가 생기네요..
물론 현재 코드에는 SO_KEEPALIVE 옵션과 Non_Blocking 소켓 통신처리가 되어 있지 않습니다... 물론 이유는... 잘몰라서 ...그럽니다. 핑계이겠지요..
현재 테스트는 완전하게 거치지는 못했지만 현재 소스로도 문제가 없다면 위 두가지를 첨부해서 수정해야 하는데 감을 잡지 못하겠네요...
급하다고 이런식으로 해서는 않되는거 알지만..쓴소리도 달게 받을테니 지도 부탁드립니다.

동작은 2000번 포트로 서버가 대기하고 있다가 클라이언트들이 접속요청이 들어오면 accept 해주고 들어오는 data 대로 mysql 에 INSERT 또는 UPDATE 해주는 역할을 합니다.

서버가 가장 안정적으로 돌아야하는 부분이라서 감히 fork 와 thread 는 사용하지 않았습니다.

#include<sys/time.h>
#include<sys/socket.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<unistd.h>
#include<stdlib.h>
#include<stdio.h>
#include<string.h>
#include<netinet/in.h>
#include<arpa/inet.h>
#include<errno.h>
#include<sys/wait.h>
#include<mysql.h>
#include<errno.h>

#define FD_SETSIZE      1024

#define DB_HOST		"localhost"
#define DB_USER		"root"
#define DB_PASS		""
#define DB_NAME		"ilweol"

#define INSERT_QUERY "INSERT INTO test (innum, sockfd, sock_name ) values ('', '%d','%s')"
#define UPDATE_QUERY "UPDATE TABLE test SET sockfd = '%d', sock_name = '%s' WHERE '%S'"
#define DELETE_QUERY "DELETE FROM 'test' WHERE '%s'"

int Result;
int UpdateDB(char databuf[255]);

int main(int argc, char **argv)
{
        int server_sockfd, client_sockfd, sockfd;

        //select 를 통해서 넘어오는 fd 의 개수
        int fd_num;

        int state, stateOpt, client_len;
        int i, maxi, maxfd, yes, rcvStr_len;

        char buff[255];          //클라이언트로부터 들어온 입력문을 저장
        char strbuf[255];

        //client 연결을 저장하기 위한 배열 - 현재 소켓 상태를 알기위함
        int client[FD_SETSIZE];			
        //현재 1024 동시 접속으로 설정 #define FD_SETSIZE 참조

        struct sockaddr_in clientaddr, serveraddr;
        fd_set readfds, allfds;

        if(argc != 2)
        {
                printf("Usage : ./server[port]\n");
                printf("ex]   : ./server 2000\n");
                exit(0);
        }

        fd_num=0;

        //INET sock connect
        if ((server_sockfd = socket(AF_INET, SOCK_STREAM,0)) < 0)
        {
                perror("socket error : ");
                exit(0);
        }

	stateOpt = setsockopt(server_sockfd, SOL_SOCKET, SO_REUSEADDR, (void*)&yes, sizeof(int));
	if (stateOpt == -1)
	{
		printf("%d 에러\n",stateOpt);
		perror("setsocketopt");
		exit(1);
	}

        bzero (&serveraddr, sizeof(serveraddr));
	//bzero (&(serveraddr.sin_zero),8);
        serveraddr.sin_family = AF_INET;
        serveraddr.sin_addr.s_addr=htonl(INADDR_ANY);
        serveraddr.sin_port = htons(atoi(argv[1]));

        state = bind (server_sockfd, (struct sockaddr *)&serveraddr, sizeof(serveraddr));
        if (state == -1)
        {
                perror("bind error :");
                exit(0);
        }
        state = listen(server_sockfd,1024);
        if (state == -1)
        {
                perror("listen error :");
                exit(0);
        }
        //INET Sock End

        client_sockfd=server_sockfd;
        maxi = -1;

        //현재 fd의 최대값을 maxfd 에 입력 - 동적
        maxfd = server_sockfd;

        //fd 배열을 -1 로 초기화
        //한 후 accept 성공하면 해당 fd 로 배열의 끝을 채운다.
        for(i = 0; i < FD_SETSIZE; i++)
        {
                client[i]=-1;
        }

        //INET 소켓 fd 에 대하여, fd_set 에 등록한다.
        FD_ZERO(&readfds);
        FD_SET(server_sockfd, &readfds);

	memset(buff,0x00,255);
        while(1)
        {
                allfds = readfds;

                fd_num = select(maxfd+1, &allfds, (fd_set *)0, (fd_set *)0, NULL);

                //만약 소켓 파일지시자에 연결이(read) 이 들어오면
                //accept 해준다.
                if(FD_ISSET(server_sockfd, &allfds))
                {
                        client_len = sizeof(clientaddr);
                        //accept
                        client_sockfd = accept(server_sockfd, (struct sockaddr *)&clientaddr, &client_len);

                        //client 매열에 현재 연결된 client_sockfd 를 입력
                        for(i=0 ; i<FD_SETSIZE; i++)
                        {
                                if(client[i]<0)
                                {
                                        client[i]=client_sockfd;
                                        printf("%d : %d\n", i, client_sockfd);
                                        break;
                                }
                        }

                        //FD_SETSIZE 를 초과해서 client가 접근할 경우 연결을 종료한다.
                        if(i==FD_SETSIZE)
                        {
                                close(sockfd);
                                client[i]=-1;
                        }

                        //fd_set 에 등록
                        FD_SET(client_sockfd, &readfds);

                        if(client_sockfd>maxfd)
                                maxfd = client_sockfd;

                        if(i>maxi)
                                maxi=i;
                        if(--fd_num <= 0)
                                continue;
                }
                //client 배열에 입력된 fd 중
                //연결된(-1이 아닌) fd 에 대해서
                //읽을 데이타가 있는지 검사한 후
                //있으면 처리한다.
                for(i=0; i<=maxi; i++)
                {
                        if((sockfd = client[i])<0)
                        {
                                continue;
                        }

                        printf("maxi %d\n", maxi);
                        if (FD_ISSET(sockfd, &allfds))
                        {
                                //파일 stream pointer 를 첨으로 돌린다.
                                if (read(sockfd, buff, 255) <=0)
                                {
                                        close(sockfd);
                                        FD_CLR(sockfd, &readfds);
                                        client[i]=-1;
                                }
                                else
                                {
                                        //client가 quit를 입력하면
                                        //연결을 종료한다.

                                        if(strncmp(buff, "quit",4)==0)
                                        {
                                                write(sockfd, "bye bye", 8);
                                                close(sockfd);
                                                FD_CLR(sockfd, &readfds);
                                                client[i] = -1;
                                                break;
                                        }
					printf("%s\n",buff);//읽은 데이터의 처리부분
					//CRC 체크 및 checksum
					Result = UpdateDB(buff);//sql 처리 부분
					usleep(1);
					if (Result == 1)
					{
						write(client_sockfd, "MSG Received", 255);
					}
					else
					{
						write(client_sockfd, "Failed DB Update", 255);
					}
	                                printf("전송 완료\n");
					//데이타 버퍼 초기화
					memset(buff,0x00,255);
                                }
                                if(--fd_num <=0 )
                                        break;
                        }
                }
        }
}

int UpdateDB(char databuf[255])
{
	char qbuf[512];
	MYSQL *conn,mysql;

	mysql_init(&mysql);
	memset(qbuf,0x00,512);
	if((conn=mysql_real_connect(&mysql, DB_HOST, DB_USER, DB_PASS, DB_NAME, 3306, (char *)NULL, 0))==NULL)
	{
		printf("연결에러 : %s\n", mysql_error(&mysql));
		return(0);
	}

	//update 부분
	if(strncmp(databuf,"insert",6)==0)
	{
		sprintf(qbuf,INSERT_QUERY,1,databuf);
	}
	else if(strncmp(databuf,"update",6)==0)
	{
		sprintf(qbuf,UPDATE_QUERY,1,databuf,"innum = '1'");
	}
	else
	{
		printf("선택된 쿼리 없음\n");
	}

	if(mysql_query(conn,qbuf))
	{
		//fprintf(stderr,"질의 실패 : %s\n", mysql_error(conn));
                printf("질의 실패 : %s\n", mysql_error(conn));
		mysql_close(conn);
		return(0);
	}
	mysql_close(conn);
	return(1);
}

bugiii의 이미지

무엇이 궁금한 것인가요?

jiheony의 이미지

이 소스를 1 대 다 서버로 사용을 해도 괜찮은지를 묻고 싶은건데요..
또 문제가 이 소스에서는 문제가 발생한 소켓을 처리하는 부분이 없다는 거죠..

예를 들어 예기치 못한 일들로 클라이언트로의 접속이 끊긴다거나..
아니면 해제되지 못한 빈 소켓들이 닫히지 않고 있다거나..
했을때 그부분을 어떻게 처리해야하는지가 궁금한겁니다.

jiheony의 이미지

참고로 컴파일 옵션은 mysql 옵션을 따라주시면 됩니다.

제 path 에서는 다음과 같습니다.

gcc -o server p_server.c -I/usr/local/mysql/include/mysql -L/usr/local/mysql/lib/mysql -lmysqlclient

liongo의 이미지

밥시간인 관계로 자세히는 못봤으나 넘 복잡 ㅜ.ㅜ

                                //파일 stream pointer 를 첨으로 돌린다. 
                                if (read(sockfd, buff, 255) <=0) 
                                { 
                                        close(sockfd); 
                                        FD_CLR(sockfd, &readfds); 
                                        client[i]=-1; 
                                } 

이부분에서 소켓이 끈어지는걸 처리하는것 같은데요?

select에서 소켓이 끈어지는 이벤트를 주기때문에.. 놓치면 안됩니다 -_-

해제하지 못한 소켓이 생기면 안된다는것이지요.

상대방 컴이 통신중 꺼져버리면 문제가 생길수있습니다 ㅡㅡa

체크해본지 오래되서 기억이 가물가물거리나.. 이벤트를

못잡을수있습니다.. 고로 클라이언트의 접속정보를 주기적으로 체크해서..

지정시간동안 응답이 없는 클라이언트는 해제하는 방식으로 처리하시면 됩니다..

밥땜시 이만 휙.

' 형식이 내용을 규정한다. '

jiheony의 이미지

아무런 코멘트가 없어서...걱정이었는데...
select 에 그런 문제가 있게 되는군요......

그럼 setsockopt 에서는 그런 경우를 잡지 못하는건가요?

아니면 루프돌면서 체크를 해야하는 건지...

liongo의 이미지

네 보통 서버들은 클라이언트로부터 정해진 시간동안 응답이 없으면

접속을 끊습니다. 아니면 중간에 Ping을 두어서 서로 살아있는지

체크를하지요..

일반적으로 A <-> B 연결상태에서도 소켓이 끈어지거나 하는것에대해

A가 B에게 물어봅니다.. B가 대답을 안해주면 A가 바로 알아채지 못합니다..

' 형식이 내용을 규정한다. '

jiheony의 이미지

방법은 keepalive 옵션을 주고 연결되어 있는 소켓들 중에서...read 또는 recv 동작 바로전에 연결이 되어 있는지 확인 하는게 있을것 같은데...
그게 가능한가요?

liongo의 이미지

글재주가 딸려서 검색하여서 JAVA API에 설명문구를 훔쳐옵니다..

제가 KEEPALIVE를 사용해본적이 없어서.. 고수님들이 추가설명 붙여주실듯 :)

설명은 비슷할것같아서 가져왔습니다.. 참고만하시길..

Quote:
TCP 소켓에 KeepAlive 옵션이 설정되어 있고, 소켓을 개입시켜 어느쪽향에도 데이터가 2 시간 (주: 실제의 값은 구현에 의한)의 사이 교환되어 있지 않은 경우, TCP 는 자동적으로 KeepAlive probe를 피어에 송신합니다. 이 probe는, 피어가 응답할 필요가 있는 TCP segment입니다. 다음의 3 개(살) 중의 어떤 것인가가 생각됩니다. 1. 피어는 예상되는 ACK 로 응답한다. 만사 지장 없기 때문에, 어플리케이션에는 통지하지 않는다. TCP 는, 게다가 2 시간 데이터 교환을 하지 않으면 probe를 송신한다. 2. 피어는, 피어 호스트가 크래쉬 해 재기동한 로컬 TCP 를 나타내는 RST 로 응답한다. 소켓은 닫혀진다. 3. 피어로부터의 응답이 없다. 소켓은 닫혀진다. 이 옵션의 목적은, 피어 호스트가 크래쉬 할 경우에 검출하는 것입니다.

p.S

정확한 사용법(?) 을 숙지하시고 사용하시기 바랍니다. 대충 짐작하시고 사용

하시는것은 차후에 원인불명의 오동작을 일으키는 버그를 일으킬수 있습니다.

' 형식이 내용을 규정한다. '

bugiii의 이미지

select 류는 각각의 fd 에 타임아웃을 줄 수 없습니다. 각 fd 마다 타임아웃을 따로 보관하는 자료구조를 만들고 가장 짧은 타임아웃을 select 의 타임아웃으로 주면서 조사해야 하는데 좀 복잡해질 수 있습니다.

그리고, mysql 의 C API 는 select 류 하고는 좀 맞지 않습니다. 쿼리하는 함수들이 블러킹되기 때문에 쓰레드 모델을 요구하고 있습니다. 기껏 클라이언트의 입력과 출력을 다중화 방법으로 처리를 하더라도 실제로 시간이 가장 많이 걸릴 DB 쿼리시 모든 접속이 블럭된다면 아무런 효과를 보지 못할 것입니다.

PostgreSQL 은 쿼리 함수들이 넌블러킹을 어느정도 지원해서 가능하기는 합니다.

만드시려는게 mysql 의 미들웨어 정도라고 생각되는대요. DB의 접속당 쓰레드를 만들고 이것을 쓰레드 풀링하는 방법을 사용하셔야 할 것 같습니다. 클라이언트의 접속은 select 로 다중화하고 이것과 쓰레드 풀과의 통신을 select 에 같이 포함시켜서 처리하는 과정이 필요할 것 같습니다.

좀 다르게 한다면, 저는 이런 역할을 두 프로세스로 나눠서 했는데요. 일단 DB 접속하고 쿼리하는 다중 쓰레드 프로세스를 하나 만들고요. 실제 클라이언트 접속을 받는 다른 프로세스가 이 db 미들웨어에 db 커넥션 풀을 이용해서 소켓 통신하도록 하였습니다. 분리를 하니까 생각하기가 좀 쉬웠습니다.

liongo의 이미지

헛 그새답변이..

bugiii님 역시 답변의 고수 ㅡㅡa

저는 단지 공부 용도및 과제(?) 수준으로 생각햇는데... 이런..

넓은 안목으로 질문을 보시는군요.. 감탄.. 제생각이 짧았습니다.

' 형식이 내용을 규정한다. '

bugiii의 이미지

Quote:
mysql 4.1.x 에 INSERT DELAYED라는 옵션이 생겼습니다.

블러킹되지 않습니다. mysql이 일단 큐에 넣었다가 처리합니다..


아 그런것이 있었군요. 그러면 해당 쿼리가 완료/에러 되었다는 것을 효과적으로 알 수 있는 방법도 제공하나요? 그렇다면 아주 좋은 모델이 될 수 있겠는데요. 어떻게 동작하는지 정말 궁금합니다. 경험담을 부탁드립니다.

p.s. 할 일없이 게시판만 보고 있는... (아.. 할 일은 많은데 하지 않는다는 것이 더 정확) 넓은 안목... 부끄러울 따름입니다. 여기 kldp 의 높은 경지에 도달하신 여러분들에 비해서는 아직도 멀었다는 생각을 많이 합니다. 게시물을 보다보면 흠칫흠칫 놀랄 때가 한두번이 아닙니다. 자극 받기 위해서도 게시판을 주시하고 있는지도...

liongo의 이미지

:) 아 select건도 있어서 불필요한거 같아서 지웠는데 보셨군요..

재밋는 옵션이긴하죠 저도 솔깃해서 사용하게 됬습니다.. 경험담까진 안되고..

회사에.. 초당 500 건 정도 되는 로그를 쌓아야 하는 일이 생겼습니다..
사용하는 쿼리는 ONLY INSERT, UPDATE
귀차니즘에 서버를 짜기 싫어서 MYSQL로 바로 넣엇더니 로드가 올라가서요..
새벽에도는 통계프로그램 로드랑 lock에 문제요소가 많이 보이더군요..
innodb + bufferd(?) server로 고려하면서 구상을 하고있었죠..
그런데 자료를 찾아보던중 흥미로운 쿼리문을 찾았습니다..

INSERT DELAYED INTO adlog_%04d%02d( uid, page, cnt, _time, is_guest ) values( '%s', '%s', 1, now(), '%d' ) ON DUPLICATE KEY UPDATE cnt=cnt+%d http://dev.mysql.com/doc/mysql/en/INSERT.html

블러킹이 되지 않으며 키가 겹칠경우 UPDATE를 해주는 -_- 저에게 필요한거였죠..

그래서 중간에 서버가 겹치는 키는 가지고 있는 녀석들중 찾아서 cnt++ 해줘서 쿼리수는 줄이고 분마다 모아서 디비로 들이부어넣는 식으로 처리했습니다..
innodb 회사에서 못쓰게해서 ㅡㅡa myisam을 썻는데 table lock땜시 고민하다가..delayed queue 사이즈 조정을 할수있더군요
그걸로 -_- 해결봤지요..
서버는 단순히 Thread Pool 모델이었습니다. 디비 덤핑용 쓰레드하나랑.. DB POOL
4.1은 alpha였지만 -_-;; 현재 문제 없이 잘돌구있네요.. 빨리 베타라도 나오길..

아차 그리고 쿼리문에 문제가 있으면 에러는 바로 리턴해줍니다.
해당 테이블이 없거나 컬럼들이 맞지 않으면요 거기까지 맞으면..
대기열에 들어갑니다.

p.s 저도 할일이 없었는지 쓸때없는 내용까정 주저리주저리 길어졌군요 ㅡㅡa

' 형식이 내용을 규정한다. '

bugiii의 이미지

네. 좋은 경험 고맙습니다. 그럼 그 쿼리가 끝난 것을 어떻게 판별하나요? 확인할 방법은 없는건가요? 일반적인 로그라면 상관없겠지만 조금 민감하거나 꼭 제대로 써져야 하는 것 같은 경우에는 조금 곤란하지 않을까요? mysql API 를 쓰레드 쓰지않고 select 류하고 잘 어울리게 사용할 방법이 없을까 궁금합니다.

아... 아차... 글을 못봤군요. 바로 리턴되는군요... 그렇다면, 기록중 에러는 날 확률이 없다는 것인가요?

p.s. 대만 전시회 참가를 해서 부쓰를 지키는 입장이라 뭘 찾아볼 시간이 없습니다. 괜히 귀찮게 해드리는 것 같아서 죄송스럽습니다...

liongo의 이미지

네.. 바로체크되는것과 안되는것이 있는데

제경우는 중복키 에서 에러날부분을 ON DUPLICATE KEY UPDATE

로 잡아놔서 쿼리상에러는 없다고 봐도 문제가 없기때문에..

처리가 가능했구요 중복키에러는 UPDATE로 처리할것이 아니라면

못잡을것같습니다.. 비슷한 에러들도.. 쿼리도중 나는것들 말이죠..

(테이블이..풀이라든가 등등..쿼리 도중 나는 에러들 )

쿼리전에 문법체크정도 수준은 바로 잡아낼수있죠.. 제경우느 테이블이 없

는경우는 에러를 잡아서 해당 월의 테이블을 생성하거든요.

그리고 DELAYED 시에 큐가 꽉차면 비어질때까지 기다렸다가 넣기때문에..

큐사이즈를 넉넉하게 잡으시면 이론상 가능한 이야기같습니다..

p.s 본문 질문과 관련이 조금은 있는듯해서 리플답니다.. ㅡㅡa

http://dev.mysql.com/doc/mysql/en/INSERT_DELAYED.html

여기보시면 제약사항과 설명이 있습니다..

휴우 대만에 계신건가요? 전시회라 흥미롭습니다 +_+

' 형식이 내용을 규정한다. '

jiheony의 이미지

두분 정말 감사합니다...
아직까지도 시작에서 반도 못간것 같아서 헤메이고 있었는데...
비록 구현단계에서 버벅 거리고 있어도...
방법이라도 얻을 수 있다는거에 큰 힘이 됩니다.

다시 한번 감사드립니다.

bugiii의 이미지

본 주제하고는 상관없지만 심심해서 -_-; 호텔방에서 몇자 적어봅니다.

지금 참가하고 있는 전시회는 TAMMA 라고 해서 아케이드용 (업소용, 쉽게 말씀드리자면 오락실용) 게임기 전시회인데, 이 전시회는 거의 중국인들만의 잔치라고 보시면됩니다. 외국회사로는 거의 유일하게 6개월간 설득해서 (영업부의 얘기로) 겨우 부쓰 얻어서 전시하게 되었습니다.

분위기는 청소년용 비디오, 체감형 게임기는 거의 없고 대부분 슬롯, 카드류 등의 성인용 게임기가 주를 이루고 있어서 볼 것이 좀 없습니다. 작년은 사스의 영향으로 아주 규모가 작았는데 이번에는 아주 크게 열었더군요.

전시장은 타이페이 시청 옆 101층짜리 (101층 맞나 몰라요) 건물 옆 전시장입니다. 그 101층 건물은 불꽃 모양으로 활활 타오르는 느낌을 받았습니다. 아주 멀리서 그 건물만 보인다는... 하여튼 자기네 말로는 세계에서 가장 높다고 자랑이 이만저만이 아니더라구요. 하여튼 대만에서 하는 컴퓨터 전시로 유명한 쇼가 있는데 그것도 그 옆 이곳 전시장에서 여는 걸로 알고 있습니다.

날씨는 오후에 비오고 나머지는 구름많은 아주아주 덥고 습한 날씨라서 거리를 걷는 것은 거의 불가능에 가까울 정도입니다. 34도는 보통이고... 건물 바깥으로 나갈때의 열기는 정말이지 한증막 저리가라 입니다.

여러 전시회를 다녀보면 역시 우리나라가 살기 좋다는 걸 (언어 문제가 가장 크겠죠... -_-; ) 다시 한번 느낍니다. 뭐... 먹고 마시는 것이야 손짓 발짓으로 다 되지만 다른 걸 할 수가 없으니... 그리고, 뻘짓(?)도 우리나라에서나 가능한 것이니... 흠흠...

아... 화장빨인지는 몰라도 우리나라 여인들이 역시 낫더라는 것도 하나의 느낌이랄까요... 여기 여인들은 화장을 할 수 없는 (너무 덥고 땀도...) 환경이라 그런지 좀 낯설다고 해야 하나... 그렇더군요. 일본 여인들은 세련은 되었지만 얌체같다라는 느낌? 미국은 워낙 다양하니 취향대로겠고... 파리는 인형 느낌... 로마는 허리부분에만 눈이가는 스타일...

어우어우... 정말 삼천포로 빠지는군요... 빨리 돌아가고 싶은 생각이 간절합니다... 와이프가 kldp 하고는 전혀 상관없으니 뭐...

alwaysN00b의 이미지

bugiii wrote:
본 주제하고는 상관없지만 심심해서 -_-; 호텔방에서 몇자 적어봅니다.

지금 참가하고 있는 전시회는 TAMMA 라고 해서 아케이드용 (업소용, 쉽게 말씀드리자면 오락실용) 게임기 전시회인데, 이 전시회는 거의 중국인들만의 잔치라고 보시면됩니다. 외국회사로는 거의 유일하게 6개월간 설득해서 (영업부의 얘기로) 겨우 부쓰 얻어서 전시하게 되었습니다.

분위기는 청소년용 비디오, 체감형 게임기는 거의 없고 대부분 슬롯, 카드류 등의 성인용 게임기가 주를 이루고 있어서 볼 것이 좀 없습니다. 작년은 사스의 영향으로 아주 규모가 작았는데 이번에는 아주 크게 열었더군요.

전시장은 타이페이 시청 옆 101층짜리 (101층 맞나 몰라요) 건물 옆 전시장입니다. 그 101층 건물은 불꽃 모양으로 활활 타오르는 느낌을 받았습니다. 아주 멀리서 그 건물만 보인다는... 하여튼 자기네 말로는 세계에서 가장 높다고 자랑이 이만저만이 아니더라구요. 하여튼 대만에서 하는 컴퓨터 전시로 유명한 쇼가 있는데 그것도 그 옆 이곳 전시장에서 여는 걸로 알고 있습니다.

날씨는 오후에 비오고 나머지는 구름많은 아주아주 덥고 습한 날씨라서 거리를 걷는 것은 거의 불가능에 가까울 정도입니다. 34도는 보통이고... 건물 바깥으로 나갈때의 열기는 정말이지 한증막 저리가라 입니다.

여러 전시회를 다녀보면 역시 우리나라가 살기 좋다는 걸 (언어 문제가 가장 크겠죠... -_-; ) 다시 한번 느낍니다. 뭐... 먹고 마시는 것이야 손짓 발짓으로 다 되지만 다른 걸 할 수가 없으니... 그리고, 뻘짓(?)도 우리나라에서나 가능한 것이니... 흠흠...

아... 화장빨인지는 몰라도 우리나라 여인들이 역시 낫더라는 것도 하나의 느낌이랄까요... 여기 여인들은 화장을 할 수 없는 (너무 덥고 땀도...) 환경이라 그런지 좀 낯설다고 해야 하나... 그렇더군요. 일본 여인들은 세련은 되었지만 얌체같다라는 느낌? 미국은 워낙 다양하니 취향대로겠고... 파리는 인형 느낌... 로마는 허리부분에만 눈이가는 스타일...

어우어우... 정말 삼천포로 빠지는군요... 빨리 돌아가고 싶은 생각이 간절합니다... 와이프가 kldp 하고는 전혀 상관없으니 뭐...

헉. 34도.. :shock:

아직 초보라 항상 들어와 글만 읽고 가는데 bugiii님은 언제나 성실하고 시원시원하게 답변을 해주시는군요. 질문자의 소스코드를 보지도 않았는데 (초보라..) 답변만 보고도 뭔 내용인줄 알겠군요. 어서 고국으로 돌아오시길.. :o

언제나 시작

jiheony의 이미지

mysql 링크 건데를 보니까....

When you use ON DUPLICATE KEY UPDATE, the DELAYED option is ignored. 


이 문구가 보이네요...TT
liongo의 이미지

지금 자세히 읽어보니 그런이야기가 있군요 송구스럽습니다.

어째 mysql이 빨라서 제가 인지 못하고 있었던것 같습니다. :oops:

1기가 듀얼 램2기가 사양입니다.

Quote:
mysql> INSERT DELAYED INTO adlog_200406( uid, page, cnt, _time, is_guest ) values( 'liongo', 'top_l', 1, now(), '0' ) ON DUPLICATE KEY UPDATE cnt=cnt+1;
Query OK, 1 rows affected (0.00 sec)

mysql> select count(*) from adlog_200406;
+----------+
| count(*) |
+----------+
| 6782207 |
+----------+
1 row in set (0.00 sec)

mysql> select SUM(cnt) from adlog_200406;
+----------+
| SUM(cnt) |
+----------+
| 33697871 |
+----------+
1 row in set (12.32 sec)

mysql ver 4.1.20alpha

3일치입니다 ㅡㅡ 왠지 dsn 분위기가 나는군요..

bugiii님이 쓰신글 참조하세용 필요한 구조에대해서 적으신겁니다..

jiheony님 코드에 필요한 기술들이죠 ..

제 주절주절 경험담은 실험적 & 모험적인것이니까요..

그리고.. 제글의 오류에 대해서 다시한번 사과 드립니다.

' 형식이 내용을 규정한다. '

댓글 달기

Filtered HTML

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

BBCode

  • 텍스트에 BBCode 태그를 사용할 수 있습니다. URL은 자동으로 링크 됩니다.
  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param>
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.

Textile

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • You can use Textile markup to format text.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Markdown

  • 다음 태그를 이용하여 소스 코드 구문 강조를 할 수 있습니다: <code>, <blockcode>, <apache>, <applescript>, <autoconf>, <awk>, <bash>, <c>, <cpp>, <css>, <diff>, <drupal5>, <drupal6>, <gdb>, <html>, <html5>, <java>, <javascript>, <ldif>, <lua>, <make>, <mysql>, <perl>, <perl6>, <php>, <pgsql>, <proftpd>, <python>, <reg>, <spec>, <ruby>. 지원하는 태그 형식: <foo>, [foo].
  • Quick Tips:
    • Two or more spaces at a line's end = Line break
    • Double returns = Paragraph
    • *Single asterisks* or _single underscores_ = Emphasis
    • **Double** or __double__ = Strong
    • This is [a link](http://the.link.example.com "The optional title text")
    For complete details on the Markdown syntax, see the Markdown documentation and Markdown Extra documentation for tables, footnotes, and more.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 사용할 수 있는 HTML 태그: <p><div><span><br><a><em><strong><del><ins><b><i><u><s><pre><code><cite><blockquote><ul><ol><li><dl><dt><dd><table><tr><td><th><thead><tbody><h1><h2><h3><h4><h5><h6><img><embed><object><param><hr>

Plain text

  • HTML 태그를 사용할 수 없습니다.
  • web 주소와/이메일 주소를 클릭할 수 있는 링크로 자동으로 바꿉니다.
  • 줄과 단락은 자동으로 분리됩니다.
댓글 첨부 파일
이 댓글에 이미지나 파일을 업로드 합니다.
파일 크기는 8 MB보다 작아야 합니다.
허용할 파일 형식: txt pdf doc xls gif jpg jpeg mp3 png rar zip.
CAPTCHA
이것은 자동으로 스팸을 올리는 것을 막기 위해서 제공됩니다.