출처 : http://www.joinc.co.kr/modules/moniwiki/wiki.php/article/gdbm
프로그램 분석중 gdbm_exists 라는 함수를 발견 했습니다.
뭔가 했더니 이런게 있군요... ㄷㄷㄷ
요즘 사이트에 있어서 mysql, oracle, postgresql 등 RDBMS 가 쓰이지 않는 곳이 거의 없을정도로 많은 인기를 끌고 있다.
그 반면 NIS, BIND, sendmal, LDAP 등 많은 프로그램들이 각각의 자료를 관리하기 위해서 굳이 RDBMS 를 쓰지 않고 ndbm, dbm, gdbm 을 사용하고 있다. 왜 막강한 RDBMS를 쓰지 않고 이러한 간단한 dbm 을 쓰는걸까 ?
그 이유는 간단한 일을 하기 위해서 RDBMS 는 너무 크고 너무 거추장 스럽다는 것이다. 소규모(1000 에서 10000 건) 정도의 전화번호부를 관리한다거나, sendmail 에서 수백건 미만의 hosts(relay 허용등) db를 관리하는데에는 실지로 RDBMS의 기능의 10%도 필요하지 않다. 이러한 간단한 DB를 유지하려고, 서버에 RDBMS 를 설치하고, 운용하고, 프로그래밍을 하고, 복잡한 SQL을 사용하는건 너무 소모적인 일이다. 그래서 이러한 간단한 소규모의 데이타를 관리하기 위해서 dbm 이 존재한다.
dbm 은 관계형 데이타 구조 모델을 가지지 않고, HASH 데이타 구조 모델을 가진다. HASH 는 Key(키), Value(값) 의 한쌍으로 이루어지는 데이타의 집합으로써 키를 이용해서 데이타를 저장하고, 검색하고, 삭제하는 작업을 한다.
어찌 보면 C 에서의 pointer 개념과 비슷하다고 할수 있는데, Value 를 Key 가 가르킨다고 보면 무난할듯 하다.
RDBMS 와는 달리 하나하나의 데이타가 다른 데이타와는 별개로 존재하므로 RDBMS 처럼 데이타간의 관계에 의한 질의 언어가 필요없이 간단하게 Key만을 호출하면, 그 키에 연결된 값을 가져올수 있게된다. 기능의 한계가 명확하므로, 배워서 구현하기가 매우 쉬우며, 작고 또한 빠르다라는 장점을 가진다.
GDBM 은 GNU database mansger 로써 전통적으로 Unix 쪽에서 쓰이던 dbm 의 확장형이다.
아래의 예제는 간단한 주소록이다. 비록 간단하지만 세련된 코드는 아니지만 데이타의 입력, 검색, 삭제 등 dbm 으로써 가져야할 기본적인 기능을 살펴보는데 어려움은 없을것으로 생각된다.
예제 : address.c
datum 의 dptr 멤버는 malloc 를 이용해서 메모리를 할당하고, 자동으로 해제시켜주지 않는다. 그러므로 반드시 필요없다고 생각되는 곳에서 free 를 해줘야 메모리 누수 및 오류를 방지할수 있다.
위 코드는 매우 명확해 보이므로 별도로 설명을하진 않을 생각이다. 아리송하더라도 한번 정도 컴파일 해서 사용해보면서 코드를 보면 쉽게 이해가 될것이다.
gdbm 에 대한 자세한 내용은 man 페이지를 참고하라
컴파일 방법은 아래와 같다.
그 반면 NIS, BIND, sendmal, LDAP 등 많은 프로그램들이 각각의 자료를 관리하기 위해서 굳이 RDBMS 를 쓰지 않고 ndbm, dbm, gdbm 을 사용하고 있다. 왜 막강한 RDBMS를 쓰지 않고 이러한 간단한 dbm 을 쓰는걸까 ?
그 이유는 간단한 일을 하기 위해서 RDBMS 는 너무 크고 너무 거추장 스럽다는 것이다. 소규모(1000 에서 10000 건) 정도의 전화번호부를 관리한다거나, sendmail 에서 수백건 미만의 hosts(relay 허용등) db를 관리하는데에는 실지로 RDBMS의 기능의 10%도 필요하지 않다. 이러한 간단한 DB를 유지하려고, 서버에 RDBMS 를 설치하고, 운용하고, 프로그래밍을 하고, 복잡한 SQL을 사용하는건 너무 소모적인 일이다. 그래서 이러한 간단한 소규모의 데이타를 관리하기 위해서 dbm 이 존재한다.
dbm 은 관계형 데이타 구조 모델을 가지지 않고, HASH 데이타 구조 모델을 가진다. HASH 는 Key(키), Value(값) 의 한쌍으로 이루어지는 데이타의 집합으로써 키를 이용해서 데이타를 저장하고, 검색하고, 삭제하는 작업을 한다.
어찌 보면 C 에서의 pointer 개념과 비슷하다고 할수 있는데, Value 를 Key 가 가르킨다고 보면 무난할듯 하다.
RDBMS 와는 달리 하나하나의 데이타가 다른 데이타와는 별개로 존재하므로 RDBMS 처럼 데이타간의 관계에 의한 질의 언어가 필요없이 간단하게 Key만을 호출하면, 그 키에 연결된 값을 가져올수 있게된다. 기능의 한계가 명확하므로, 배워서 구현하기가 매우 쉬우며, 작고 또한 빠르다라는 장점을 가진다.
GDBM 은 GNU database mansger 로써 전통적으로 Unix 쪽에서 쓰이던 dbm 의 확장형이다.
아래의 예제는 간단한 주소록이다. 비록 간단하지만 세련된 코드는 아니지만 데이타의 입력, 검색, 삭제 등 dbm 으로써 가져야할 기본적인 기능을 살펴보는데 어려움은 없을것으로 생각된다.
예제 : address.c
#include <stdio.h> #include <string.h> #include <unistd.h> #include <gdbm/gdbm.h> const int FALSE = 0; const int TRUE = 1; int main(int argc, char **argv) { datum key_data; datum value_data; datum return_data; char cmd_char; int done = FALSE; GDBM_FILE dbf; int block_size = 0; int temp; char key_line[80]; char value_line[255]; key_data.dptr = NULL; value_data.dptr = value_line; if (access("/tmp/my_dic", F_OK) != 0) { printf( "사전 DB 파일이 존재 하지 않습니다" "영어 사전 DB 파일을 새로 만들겠습니까 (y/n)? "); cmd_char = getchar(); while(1) { if (cmd_char != '') { char temp; do temp=getchar(); while (temp != '' && temp != EOF); } if (cmd_char == EOF) cmd_char = 'n'; switch(cmd_char) { case 'y': dbf = gdbm_open ("/tmp/my_dic", block_size, GDBM_WRCREAT|GDBM_FAST, 00664, NULL); if (dbf == NULL) { perror("db file open error : "); exit(0); } break; case 'n': return 1; break; } if (cmd_char == 'y') break; } } else { dbf = gdbm_open ("/tmp/my_dic", block_size, GDBM_READER|GDBM_WRITER, 00664, NULL); if (dbf == NULL) { perror("db file open error : "); exit(0); } } printf("주소 관리 프로그램입니다. " "사용법이 궁금하시면 ? 를 입력하세요"); // 사용자의 키보드 입력문자열을 받아서 필요한 // 행동을 취한다. while(!done) { printf("com -> "); cmd_char = getchar(); if (cmd_char != '') { char temp; do temp = getchar(); while (temp != '' && temp != EOF); } if (cmd_char == EOF) cmd_char = 'q'; switch (cmd_char) { case 'q': done = TRUE; break; case '?': printf("i -- insert data" "f -- fetch data" "c -- data num" "d -- data delete" "q -- quit"); break; case '': printf(""); break; case 'i': if (key_data.dptr != NULL) free(key_data.dptr); printf("Key -> "); fgets (key_line, 80, stdin); key_line[strlen(key_line) - 1] = '0'; key_data.dptr = key_line; key_data.dsize = strlen(key_line) + 1; printf("Value -> "); fgets(value_line, 255, stdin); value_data.dsize = strlen(value_line) + 1; if (gdbm_store (dbf, key_data, value_data, GDBM_REPLACE) != 0) printf("Item no inserted "); printf(""); key_data.dptr = NULL; break; case 'f': if (key_data.dptr != NULL) free(key_data.dptr); printf("Key -> "); fgets (key_line, 80, stdin); key_line[strlen(key_line) -1] = 0; key_data.dptr = key_line; key_data.dsize = strlen(key_line) + 1; return_data = gdbm_fetch(dbf, key_data); if (return_data.dptr != NULL) { printf("data -> %s", return_data.dptr); free(return_data.dptr); } else printf("No Such item found. "); key_data.dptr = NULL; break; case 'c': temp = 0; if (key_data.dptr != NULL) free (key_data.dptr); return_data = gdbm_firstkey(dbf); while(return_data.dptr != NULL) { temp ++; key_data = return_data; return_data = gdbm_nextkey(dbf, key_data); free(key_data.dptr); } printf("%d 개의 자료가 있습니다", temp); key_data.dptr = NULL; break; case 'a': key_data = gdbm_firstkey(dbf); if (key_data.dptr == NULL) { printf("No one tiem found"); break; } else { printf("%s => ", key_data.dptr); return_data = gdbm_fetch(dbf, key_data); printf("%s", return_data.dptr); free(return_data.dptr); } while(1) { return_data = gdbm_nextkey(dbf, key_data); if (return_data.dptr != NULL) { free(key_data.dptr); key_data = return_data; printf("%s => ", key_data.dptr); return_data = gdbm_fetch(dbf, key_data); printf("%s", return_data.dptr); free(return_data.dptr); } else { printf("No such item found."); break; } } key_data.dptr = NULL; break; case 'd': if (key_data.dptr != NULL) free (key_data.dptr); printf("Key -> "); fgets (key_line, 80, stdin); key_line[strlen(key_line) -1] = 0; key_data.dptr = key_line; key_data.dsize = strlen(key_line) + 1; if(gdbm_delete (dbf, key_data) != 0) printf("Item not found or deleted"); key_data.dptr = NULL; break; } } printf("bye bye"); return 0; } |
위 코드는 매우 명확해 보이므로 별도로 설명을하진 않을 생각이다. 아리송하더라도 한번 정도 컴파일 해서 사용해보면서 코드를 보면 쉽게 이해가 될것이다.
gdbm 에 대한 자세한 내용은 man 페이지를 참고하라
컴파일 방법은 아래와 같다.
[yundream@localhost test]# gcc -o address address.c -lgdbm |
'리눅스 서버에 대해서' 카테고리의 다른 글
OpenMP를 이용한 병렬 프로그래밍 (0) | 2014.06.18 |
---|---|
리눅스 프로그래밍 팁 (0) | 2014.06.10 |
atomic swap ptr 처리 (0) | 2014.01.17 |
리눅스 swap 메모리 (0) | 2013.10.31 |
rsync 연결 거부 에러 났을때 처리 (0) | 2013.10.27 |