'데이타베이스'에 해당되는 글 2건

  1. 2008.05.30 GDBM을 이용한 간단한 DB프로그래밍
  2. 2008.05.30 GNU gdbm (GNU DataBase Manager) 프로그래밍
http://www.joinc.co.kr/modules/moniwiki/wiki.php/article/gdbm


요즘 사이트에 있어서 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
#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;
}

datum 의 dptr 멤버는 malloc 를 이용해서 메모리를 할당하고, 자동으로 해제시켜주지 않는다. 그러므로 반드시 필요없다고 생각되는 곳에서 free 를 해줘야 메모리 누수 및 오류를 방지할수 있다.
위 코드는 매우 명확해 보이므로 별도로 설명을하진 않을 생각이다. 아리송하더라도 한번 정도 컴파일 해서 사용해보면서 코드를 보면 쉽게 이해가 될것이다.
gdbm 에 대한 자세한 내용은 man 페이지를 참고하라
컴파일 방법은 아래와 같다. [yundream@localhost test]# gcc -o address address.c -lgdbm
Posted by stekilove
,

GNU gdbm (GNU DataBase Manager) 프로그래밍

----------------------------------------------------

 

  글쓴이   : 한동훈 ddoch@hitel.kol.co.kr   

                http://home.postech.ac.kr/~prizer/Misc/gdbm-manual.html

 

  ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ 

                                           

                                               

        1. 들어가는 말                         

        2. 도입과 전개                         

        3. 여러 함수들                         

        4. 그외의 다른 것                      

        5. 프로그램을 한번 짜봅시다            

                                                

  ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧ ▧

 

 

1. 들어가는 말

 

안녕하세요. ddoch 한동훈입니다.

 

리눅스를 사용하시면서, 데이터 처리를 많이 하실 것입니다. 예전에 DOS에서 돌아

가던 dBASE 같은 것을 사용하시던 기억이 어렴풋이 떠오르시는 분들도 계실겁니다.

많은 분들 중에서 리눅스에서 쓸만한 데이터베이스가 없나하고 찾으시는 분들도 많

이 계시더군요.

 

'디비입문'... 글쎄요..

적당한 입문책을 하나 구하셔서 보셔도 좋을 것입니다. DB에 대해 전문프로그래

머가 아닌 일반 프로그래머나 사용자라면 굳이 그럴 필요까지는 없을 겁니다.

 

잘 아시겠지만, 리눅스에서 돌아가는 관계형 데이터베이스 시스템(RDBMS, 줄여서

'RDB' 라고도 하죠)으로는 많은 것들이 있습니다. 대표적인 것으로는 공개용인

postgreSQL이 있으며, 공개용은 아닌 mSQL, 그외에 다른 툴들이 많이 있습니다.

그외에도 현재 많은 상당히 훌륭한 기능들을 가진 RDBMS들이 나오고 있는 상태

입니다. 이러한 것들은 최종사용자에게도 훌륭한 DB 매니져가 되고, 프로그래머

에게도 활용할 수 있는 다양한 기능들을 제공합니다.

 

기회가 있으면, postgreSQL 같은 것은 다음기회에 소개하기로 하고,

이번 기회에 말씀드릴 것은, 프로그래머에게 요긴한 DB 관리 툴입니다.

 

"프로그램 작성중 DB관련 부분을 어떻게 처리하십니까?" 라는 질문에, RDBMS와 연

동하여 처리하시는 분들도 계실 것이고 모든 루틴을 내부적으로 만들어서 사용하

시는 분, C 나 C++로 짜여진  DB 처리툴을 사용하시는 분들도 있을 것입니다.

저도 사실 RDBMS 나 DB 처리툴들은 잘 사용하지 않았습니다. 사용하면 좋을 텐데,

단지 귀찮다는 하나의 이유만으로 내부적으로 펑션을 만들어서 처리를 많이 해

왔던 것 같습니다.

 

하지만, 프로그램이 대형화 되고, 중요한 DB를 다룬다던지, 또는 퍼포먼스 향상,

다중 프로세스 환경에서의 여러문제 들을 해결하고 싶다면 DB 처리전문 툴이나,

RDBMS 를 사용하시길 바랍니다.

 

gdbm 은 내부적으로 DB를 전문적으로 처리하는 여러 함수로 구성된 라이브러리입

니다. GNU 'dbm'은 Philip A. Nelson 씨에 의해 쓰여졌습니다. 사실 GNU dbm은

다른 표준 UNIX dbm 인 'dbm' 이나 'ndbm'과 호환성을 유지하기 위해서 내부에 따

로 정의된 헤더파일과 라이브러리를 가지고 있습니다.

 

이 소프트웨어들은 하이텔 리눅스동 자료실('gdbm173.tgz')이나 sunsite.unc.edu

"/pub/Linux/libs/db/" 에서 찾을 수 있습니다. 현재 쉽게 구할 수 있는 gdbm

의 버젼은 1.7.3 이며, 소스를 구하셔서 설치를 하시기 바랍니다. 물론, 공유라이

브러리와 헤더파일만으로 된 바이너리 배포판으로 구해서 설치해도 gdbm 을 사용하

는 데는 지장이 없지만 혹시라도 모를 'dbm' 이나 'ndbm' 과의 호환성을 유지하기

위한 라이브러리 및 헤더파일은 빠져 있으니 주의하시기 바랍니다. gdbm 은 1.7.1

의 메뉴얼을 내부에 info 파일형식으로 포함하고 있습니다. 그외에 버클리의 'db'

도 있긴 하지만, 버클리의 db 보다는 GPL을 따르고 있는 gdbm을 사용하시기를 권장

합니다.

 

'gdbm' 을 사용하면 어떤 것이 좋을까요?

 

 1) 데이터 파일의 삭제, 갱신, 편집 등등의 관리에 직접 신경을 쓰지 않아도

    됩니다. 이 작업은 gdbm 이 최적화된 상태를 유지하면서 에러상태와 여러

    가지의 경우에 gdbm 이 내부적으로 대응하니 신경 쓸 필요는 없습니다.

 

 2) 데이터 검색에 최선의 알고리즘을 사용하므로 속도면이나 퍼포먼스 면에서

    상당한 효과를 가져올 수 있습니다. DB 를 일일이 하위 레이어까지 손으로

    짤 경우에 발생하는 각종 고효율 알고리즘을 구현하기 위해서 머리를 썩일

    필요성이 없다는 것입니다. 이 작업은 gdbm 이 최선의 효율성을 유지하면서

    해쉬테이블을 통해 대신합니다.

 

 3) DB 구축과 운용에 노력이 훨씬 적게 들어갑니다.

    gdbm 에 적절한 데이터를 넘겨줌으로써 DB 구축은 끝이 나므로 나머지 노력

    을 다른 곳에 쏟을 수 있습니다.

    물론, RDBMS 의 장점인 복잡한 관계를 처리하거나 융통성을 발휘하지는 못

    하지만 그만큼 사용이나 운용이 용이하다는 장점이 있습니다.

 

 4) 'dbm', 'ndbm' 과의 호환성을 유지하는 루틴을 가질 수 있습니다.

    gdbm 에서 제공하는 라이브러리를 사용하여 표준 UNIX 'dbm' 이나 'ndbm' 과

    호환하는 프로그램을 짤 수 있습니다. 그리고 'dbm' 이나 'ndbm' 에서 사용

    하던 데이터베이스 파일을 'gdbm' 이 사용하는 파일의 포맷으로 유틸리티를

    사용하여 바꿀 수 있습니다. 물론, GNU 'dbm' 의 기능은 더욱더 향상된 기능

    을 제공합니다.

 

 

      +-----------------+      request        +-----------------+

      |  GDBM function  |  ------------->    |  internal DB    |

      |                 |    DB name, key     |                 |

      | gdbm_open       |                     |  db create      |

      | gdbm_fetch      |      result         |  hash table     |

      | .........       |   <-------------    |  searching ...  |

      +-----------------+   modified DB       +-----------------+

    |                      return value   | |                   |

    +-------------------------------------+ +-------------------+

              User area                         GDBM Internal area

 

              [ GDBM 데이터 베이스 메니져의 개념 ]

 

 

결론적으로 말씀드리면, DB 구축이나 DB 내부에까지 프로그래머가 신경쓸 필요없

gdbm 라이브러리가 제공해주는 인터페이스 함수를 통해서 적절한 데이터만 넘

겨주면 된다는 이야기이므로 DB 프로그래밍에 아주 편리하게 사용할 수 있습니다.

 

, 12개의 함수만 익히시면 여러분들의 DB 프로그래밍에 활력소가 될 것입니다.

 

본 강좌는 gdbm 의 info 메뉴얼에 바탕하면서, 예를 들어가면서 설명하도록 하겠

습니다.

 

 

2. 도입과 전개

 

gdbm 은 표준 UNIX dbm 의 함수와 유사하게 작동하는 데이터 베이스 함수모음집

입니다. 이 함수들을 사용하여 데이터베이스 파일들을 만들거나 처리할 수 있습

니다. gdbm 의 기본적으로 key/data 를 짝으로 데이터베이스 파일에 저장하여 처

리 합니다. key 는 중복되지 않는 유일한 값이어야 하며, 각각의 key는 단 하나의

데이터아이템과 결부지어져야 합니다. key는 곧장 순서대로 정리된 상태로 접근

할 수 없습니다. gdbm 의 기본적인 유닛은 다음의 구조체입니다.

 

      typedef struct {

               char *dptr;

               int  dsize;

      } datum;

 

이 구조체는 크기가 제 각각인 key와 data 아이템을 허용합니다.

char * 형인 dptr 에 얼마던지 크고 복잡한 구조체라도 주소를 저장하여 값을 꺼

집에 낼때는 형변환하여 사용할 수 있습니다.

 

key/data 는 한짝으로 gdbm 의 디스크 파일에 저장이 됩니다. 이것은 gdbm 데이터

베이스라고 부릅니다. 하나의 응용 프로그램이 데이터베이스의 key와 data를 처리

하기위해서는 gdbm 데이터베이스를 열어야 합니다. 당연한 이야기겠지요..

또한, gdbm 에서는 하나의 어플리케이션이 동시에 여러 데이터베이스를 여는 것이

가능합니다. 하나의 어플리케이션이 한개의 gdbm 데이터베이스를 열 때, 그것은

'reader' 나 'writer'로 나타낼 수 있습니다. 보통 gdbm 데이터베이스는 한번에

하나의 writer에 의해 많이 개봉됩니다. 그러나, 많은 reader 들은 해당 데이터

베이스를 동시에 열 수 있습니다. reader 와 writer 는 동시에 gdbm 데이터베이스

를 열지는 못합니다.

 

gdbm 은 데이터베이스를 다루기위해서 다음의 함수들을 지원합니다. 함수이름과

인자들에서도 그 역할을 짐작할 수 있을 것입니다. 12개 정도의 함수셋이니 그리

많은 것은 아닐 겁니다. 이 함수들은 'gdbm.h'에 선언되어 있는데, 'gdbm.h'는

설치시 '/usr/include' 나 '/usr/local/include' 에 위치 할 것입니다.

 

    #include <gdbm.h>

   

    GDBM_FILE gdbm_open(name, block_size, flags, mode, fatal_func);

    void gdbm_close(dbf);

    int gdbm_store(dbf, key, content, flag);

    datum gdbm_fetch(dbf, key);

    int gdbm_delete(dbf, key);

    datum gdbm_firstkey(dbf);

    datum gdbm_nextkey(dbf, key);

    int gdbm_reorganize(dbf);

    void gdbm_sync(dbf);

    int gdbm_exists(dbf, key);

    char *gdbm_strerror(errno);

    int gdbm_setopt(dbf, option, value, size)

 

 

3. 여러 함수들

 

 1) 데이터 베이스 열기

 

  여기에서는 gdbm 시스템을 초기화시키는 것을 설명합니다. 초기화 루틴실행 후에

  0 바이트짜리 파일이 생겼다면 정상적으로 수행된 것입니다.

  'gdbm' ㅤ파일을 개봉하는 프로시져는 다음과 같습니다.

 

  GDBM_FILE dbf;

  dbf = gdbm_open(name, block_size, flags, mode, fatal_func);

 

  각각의 파라메터는 다음과 같습니다.

 

  char *name

    파일의 완전한 이름. gdbm 에서는 확장자 개념도 없으며 특별한 확장명을 뒤

    에 붙이지도 않습니다.

 

  int block_size

    이것은 초기화 할 동안 다양한 생성을 위한 크기를 결정하기 위해 사용합니다.

    실제적으로는 디스크에서 메모리로 한번에 전송하는 크기를 나타냅니다. 이전

    에 그 파일이 초기화 되었다면 이 인자는 무시되며, 최소값은 512이며, 만일

    이 인자의 값이 512보다 작다면 해당 파일 시스템의 블록사이즈가 사용되며,

    다른 경우는 block_size 값이 사용됩니다.

    따라서, 최대의 효율을 낼 수 있는 크기를 지정하면 좋을 것입니다.

 

  int flags

    flags 가 GDBM_READER 로 세트되어 있으면, 단지 데이터베이스 파일을 읽기만

    을 할 수 있습니다. 따라서 'gdbm_store', 'gdbm_delete' 루틴을 호출하면 당

    연히 실패하게 됩니다.

    많은 reader 들은 또한, 동시에 한 데이터베이스에 접근할 수 있습니다.

    flags 가 GDBM_WRITER 이면, 데이터베이스를 읽고 쓰기를 모두 할 수 있으며,

    배타적인 접근이 필요합니다. (동시에 한파일에 쓰기를 시도할 경우, 어떤 불

    상사가 일어나는 지는 추축에 맡기겠습니다. :))

    flags 가 GDBM_WRCREAT 로 세트되어 있으면, 데이터베이스를 읽고 쓰기를 모두

    할 수 있으며, 데이터베이스가 존재하지 않는다면, 새로운 것을 하나 만듭니

    다.

    flags 가 GDBM_NEWDB 로 세트되어 있으면, 데이터베이스가 기존에 있는지 없는

    지에 상관하지 않고 새로운 것을 하나 만들며, 읽기 쓰기를 모두 할 수 있습

    니다.

    모든 writer (GDBM_WRITER, GDBM_WRCREAT, GDBM_NEWDB) 에는 GDBM_FAST 플래

    그를 추가로 세팅할 수 있습니다. 이 옵션은 최대한의 지연쓰기를 함으로써

    속도상의 잇점을 가져오는 역할을 합니다. 따라서, 이 옵션을 사용하면, 속

    도상의 잇점은 가져올 수 있으나 writer 가 비정상적인 중단을 할 경우에는,

    데이터가 일치하지 않을 수도 있습니다.

    만일 에러가 발생했다면, NULL을 리턴값으로 돌려주고, 적당한 값이

    gdbm_errno 에 세트가 될 것입니다. 에러가 없다면, gdbm 파일 디스크럽트

    포인터가 리턴됩니다.

 

  int mode

    파일 모드. (chmod(2)와 open(2)에서 사용하는 파일모드) 

 

  void (*fatal_func) ()

    치명적인 에러가 발생하였을 경우에 gdbm 이 호출할 함수입니다. 이 함수의

    인자는 문자열만이 가능합니다. 그 값이 NULL이라면 gdbm 이 제공할 것이며,

    gdbm 은 기본 함수를 사용합니다.

 

 

리턴값인, 'dbf' 는 gdbm 파일에 접근하는 다른 모든 함수들이 사용하는 포인터

입니다. 만일 리턴값이 NULL 이라면, gdbm_open 은 실패한 것이며, 에러는 gdbm

에러를 세트하는 gdbm_errno 와 파일 시스템의 에러가 표시되는 errno 에 세트됩

니다.  (에러코드는 'gdbm.h'를 참조하세요.)

 

이후에서 설명하는 모든 호출들에 있어서 'dbf' 는 gdbm_open 이 리턴한 포인터를

참조합니다.

 

 2) 데이터베이스 닫기

 

열었으면 닫는 것은 당연한 것이겠죠? 무더운 여름도 다가오는 데 냉장고에서 시원

한 수박을 한덩어리 꺼내고는 문을 안닫아놓으면, 다음에 시원한 음료수를 빼먹

을 수 없을 겁니다. :)

 

여러 라이브러리 함수들을 사용하시다 보면, 기본적으로 초기화부분(init 또는

open), 처리부분, 마무리부분(close 또는 free..)으로 되어 있는 경우가 많습니다.

 

gdbm 라이브러리에도 닫는 함수는 있습니다.

 

    gdbm_close(dbf);

 

  GDBM_FILE dbf

  유일한 하나의 인자는 gdbm_open 에서 리턴된 포인터입니다.

 

gdbm_close 가 호출되면 gdbm 파일을 닫고 'dbf' 에 할당된 모든 메모를 자유롭

게 합니다.

 

 3) 데이터베이스에 삽입 또는 대체

 

gdbm_store 는 데이터베이스에서 레코드를 삽입하거나 대체하는 역할을 합니다.

 

    ret = gdbm_store(dbf, key, content, flag);

 

각각의 인자는 다음과 같습니다.

 

  GDBM_FILE dbf

    gdbm_open 이 리턴한 포인터

 

  datum key

    `key' 데이터

 

  datum content

    key 와 관련되는 data

 

  int flag

    이 플래그는 데이터베이스에서 해당 key 가 이미 있을 경우에 취할 행동을

    정의하는 역할을 합니다.

    GDBM_REPLACE 는 이미 있는 data를 새로운 'content' 로 대체합니다.

    GDBM_INSERT 는 'key' 가 이미 있을 경우에 아무 행동도 하지 않고 에러를

    리턴하도록 합니다.

 

  리턴된 'ret' 의 값은 다음과 같습니다.

 

  -1

    호출자가 공식적인 writer 가 아니거나, 'key' 나 'content' 에 NULL 필드를

    지정하여 데이터베이스에 아이템을 저장하지 못한 경우입니다.

    'key' 와 'content' 둘다 NULL 값이 아닌 데이터 포인터(dptr) 필드를 가져

    야 합니다. 다른 함수가 NULL 데이터포인터(dptr) 필드를 에러를 검사하기

    위해 사용하였다면, NULL 필드는 유용한 데이터가 될 수 없습니다.

 

  +1

    인자 'flag' 가 GDBM_INSERT 이고 'key' 가 이미 데이터베이스에 있어서 아이

    템이 저장되지 못한 경우입니다.

 

  0

    성공적일 경우. 'content' 는 'key' 와 연관되었으며, 디스크상의 파일이 업

    데이트되어서 새로운 데이터베이스의 구조는 이 함수가 리턴하기 전부터 영향

    을 미칩니다.

 

  만일, 데이터베이스에 이미 있는 'key' 에 해당된 데이터를 저장한다면, gdbm은

  GDBM_REPLACE 가 세트되어 있는 경우에,  오래된 데이터를 새로운 데이터로 대

  체할 것입니다.

  아울러, 하나의 같은 key 값에 두개의 데이터 아이템을 지정할 수 없으며, 이럴

  경우에 gdbm_store 는 에러를 발생하지 않습니다.

 

  gdbm 의 크기는 'dbm' 이나 'ndbm' 과 같이 제한되지는 않습니다. 여러분들의

  데이터는 원하는 만큼 크게 만들 수 있습니다.

 

 

 4) 데이터 베이스에서 레코드를 검색하기

 

  데이터베이스를 검색하는 함수는 gdbm_fetch 함수입니다. 이 함수는 주어진

  키값으로 이와 관련된 정보를 리턴합니다. 리턴된 구조체의 포인터는 동적으로

  할당된 메모리 블록을 가르키는 포인터입니다.

 

      content = gdbm_fetch(dbf, key);

 

  각각의 인자는 다음과 같습니다.

 

  GDBM_FILE dbf

    gdbm_open 에서 리턴된 포인터

 

  datum key

    key data

 

 'content' 에서 리턴된 datum 은 발견된 데이터에 대한 포인터 입니다. 만일 데이

 터 포인터(dptr)가 NULL 이라면 데이터를 발견하지 못한 것입니다. 데이터포인터

 (dptr) 가 NULL 이 아니라면 dptr 은 할당된 데이터를 가르킵니다. 'gdbm' 은

 자동적으로 이 데이터를 메모리 헤제 하지는 않습니다. 여러분들은 이것을 다 사

 용하고 나서 자유롭게 만들어야 합니다. 이러한 장점은 나중에 다시 사용하기 위

 해서 이 결과를 복사할 필요가 없다는 이야기입니다. 포인터만 저장하면 나중에

 다시 사용할 수 있겠지요.

 

 gdbm_fetch 와는 조금 다르게 간단하게 해당하는 key 에 대응하는 데이터가 있는

 지를 간단하게 살표볼 수도 있습니다.

 

      ret = gdbm_exists(dbf, key);

 

 해당 인자는 다음과 같습니다.

 

 GDBM_FILE dbf

  gdbm_open 에서 리턴된 포인터

 

 datum key

  'key' data

 

 이 루틴은 어떠한 메모리도 할당하지 않으며, 단지 해당하는 'key' 가 존재하는

 지 하지 않는 지에 따라 true 나 faluse 를 리턴합니다.

 

 5) 데이터베이스에서 레코드 제거하기

 

  데이터베이스에서 레코드를 제거하기 위해서는 다음과 같이 하면 됩니다.

 

      ret = gdbm_delete(dbf, key);

 

  각각의 인자는 다음과 같습니다.

 

  GDBM_FILE dbf

    gdbm_open 에서 리턴된 포인터

 

  datum key

    'key' 데이터

 

  아이템이 없거나 요청자가 reader 라면 ret 값은 -1 입니다. 성공적으로 제거했

  다면 0을 리턴합니다.

 

  gdbm_delete 는 key 에 관련된 아이템과 key 를 데이터베이스 'dbf' 에서 제거를

  합니다. 디스크상의 파일은 업데이트되고 새로운 데이터베이스의 구조는 이 함수

  가 리턴하기전 부터 영향을 미칩니다.

 

 6) 레코드에 연속적으로 접근하기

 

  다음의 두개의 함수는 데이터베이스에서 모든 아이템을 접근할 수 있습니다.

  이러한 접근은 'key' 값이 연속되지 않습니다. 그러나 데이터베이스에서 모든

  'key' 를 한번 방문한다는 것은 보증합니다. 방문하는 순서는 해쉬 값과 관련

  이 있습니다. gdbm_firstkey 는 데이터베이스에서 모든 키를 방문하기 시작하

  는 역할을 합니다. gdbm_nextkey 는 'dbf' 의 해쉬 구조에서 다음 엔트리를 발

  견하고 읽어들입니다.

 

      key = gdbm_firstkey(dbf);

 

      nextkey = gdbm_nextkey(dbf, key);

 

  각각의 인자는 다음과 같습니다.

 

  GDBM_FILE dbf

    gdbm_open 에서 리턴된 포인터

 

  datum `key'

  datum nextkey

    'key' data

 

  리턴값은 둘다 datum 형입니다. 만일 key.dptr 이나 nextkey.dptr 이 NULL이라면

  , 첫번째 'key' 나 다음 'key' 가 없을 경우입니다. dptr 포인터는 malloc 에

  의해 할당된 데이터에 대한 포인터이며 gdbm 은 그것을 알아서 free 하지 않는

  다는 것을 다시 한번 유의하세요.

 

  이 함수들은 데이터베이스를 읽기모드 알고리즘으로 방문한다고 합니다.

 

  파일 '방문' 은 해쉬테이블에 기초합니다. gdbm_delete 는 해쉬 테이블을 재정

  렬합니다. 원래 key 의 순서는 모든 경우에 있어서 변경되지 않은 채로 남아있

  다는 것을 보증하지는 못합니다. 만약 루프가 다음과 같이 실행된다면 어떤 몇

  몇 key 는 방문하지 않게 만들 수도 있습니다.

 

        key = gdbm_firstkey ( dbf );

        while ( key.dptr ) {

          nextkey = gdbm_nextkey ( dbf, key );

          if ( some condition ) {

            gdbm_delete ( dbf, key );

            free ( key.dptr );

          }

          key = nextkey;

        }

 

 7) 데이터베이스의 동시성

 

  데이터베이스를 처음에 GDBM_FAST 플래그로 열었다면, gdbm 은 변경된 내용이

  디스크로 완전하게 쓰여지기를 기다리지 않습니다. 이를 경우 어플리케이션이

  비정상적인 중단이 되었을 때 데이터베이스가 변조될 위험성을 가지고 있습니

  다. 다음의 함수를 사용한다면 현재에 변화된 모든 것들을 해당 데이터베이스

  파일로 쓰기를 할 수 있습니다.

 

    gdbm_sync(dbf);

 

  쉘명령에서 'sync'로 지연쓰기 된 것을 디스크로 쓰는 것과 비슷합니다.

 

  GDBM_FILE dbf

    gdbm_open에서 리턴된 포인터

 

  이 함수는 보통 많은 변화가 있고 난 다음에, 오랜시간동안 wait 를 하기 이전에

  호출합니다.

  gdbm_close 는 자동적으로 'gdbm_sync' 를 호출한것과 같은 효과를 가지며, 데

  이터베이스에서 변화가 있고난 다음에 즉각적으로 닫혔다면 더이상의 호출은 필

  요없습니다.

 

 8) 에러 메시지

 

  gdbm 의 에러코드를 에러 문자열로 변환하기 위해서는 다음 루틴을 사용해야 합

  니다.

 

      ret = gdbm_strerror(errno)

 

  gdbm_error errno

    gdbm 에러코드. 보통 gdbm_errno 입니다.

 

  이 함수는 사용자가 읽을 수 있는 문자열을 반환합니다.

 

 9) 옵션 세팅하기

 

  gdbm 은 현재 열려져 있는 데이터베이스상에서 어떤 옵션을 새로이 설정할 수

  있는 능력을 제공합니다.

 

      ret = gdbm_setopt(dbf, option, value, size)

 

  각각의 인자의 의미는 다음과 같습니다.

 

  GDBM_FILE dbf

    gdbm_open 에서 리턴된 포인터

 

  int option

    세트될 옵션

 

  int *value

    'option' 이 세트될 값에 대한 포인터

 

  int size

    'value' 에 의해 포인터되는 데이터의 길이

 

  유효한 옵션은 다음과 같습니다.

 

  GDBM_CACHESIZE - 내부 버킷 캐쉬 사이즈를 설정합니다. 이 옵션은 GDBM_FILE

                   디스크럽트당 한번씩만 설정될 수 있습니다. 그리고 데이터

                   베이스를 처음 접근한 이후로는 100으로 자동으로 세팅됩니

                   다.

 

  GDBM_FASTMODE -  fast mode 를 켜거나 끕니다. 이 옵션을 사용하면 이미 열려

                   서 활성화된 데이터베이스에서 fast mode 를 토글할 수 있습

                   니다.

                   value 는 TRUE 나 FALSE 로 세팅합니다.

 

  함수의 수행이 실패되었을 때에는 -1 이 리턴되며, 성공적일 경우에는 0을 리턴

  합니다. 실패했을 경우 전역변수인 gdbm_errno 가 적절하게 세팅됩니다.

 

  예를 들면, gdbm_open 을 사용하여 이미 열려져 있는 데이터 베이스를, 이전에는

  어떻게 접근되었던지간에, 케쉬 10을 사용하여 세팅한다면, 다음과 같은 코드가

  될것입니다.

 

        int value = 10;

        ret = gdbm_setopt(dbf, GDBM_CACHESIZE, &value, sizeof(int));

 

 

  이제 gdbm 의 12개 함수를 다 알아보았습니다.

 

  다음으로 그외의 간단한 몇가지를 알아보겠습니다.

 

4. 그외의 다른 것

 

 1) 두가지 유용한 변수

 

  * gdbm_error gdbm_errno

 

    이 변수는 gdbm 에서의 에러에 대한 정보를 가지고 있습니다.

    gdbm.h 에 이러한 에러 값들에 대한 정의가 들어 있습니다.

 

  * const char * gdbm_version

 

    버젼 정보를 가지고 있는 문자열입니다.

 

 2) UNIX 표준 dbm 과 ndbm 과의 호환성

 

  GNU 'dbm' (gdbm) 파일은 엉성하지 않습니다. 여러분들은 UNIX 'cp' 명령을 사용

  하여 복사할 수 있으며, 또한 복사하는 프로세스가 확장하지도 않습니다.

 

  gdbm 파일은 UNIX 'dbm' 과 'ndbm' 을 사용하는 프로그램에 있어서 호환모드가

  있습니다.

 

  GNU 'dbm' 은 'dbm' 과 호환되는 함수를 가지고 있습니다. 'dbm' 과의 호환성을

  위해서는, 여러분들은 'dbm.h'를 포함해야 합니다.

 

  호환 모드에 있어서는, gdbm 파일 포인터가 사용자에게 필요치 않으며, 한번

  에 단 하나의 파일만이 열릴 수 있습니다. 호환모드에 있어서 모든 사용자들은  

  writer 로 간주됩니다. gdbm 파일이 읽기모드라면, 그것은 writer 로서 실패할

  것이나, reader 로서 그것을 열기를 시도할 것입니다. 데이터를 가르키는 datum

  구조제에서 리턴된 모든 포인터는 gdbm 이 free를 할 것입니다. 그 포인터들은

  static 포인터로 취급되어야 합니다. 표준 UNIX 'dbm' 이 그런것 처럼 말입니다.

  호환되는 함수의 이름은 UNIX dbm 함수의 이름과 같습니다. 아래에서 보이는 것

  처럼....

 

    int dbminit(name);

    int store(key, content);

    datum fetch(key);

    int delete(key);

    datum firstkey();

    datum nextkey(key);

    int dbmclose();

 

  표준 UNIX 의 'dbm' 과 GNU 'dbm' 은 파일의 데이터 구조가 다릅니다.

  * 여러분들은 표준 UNIX 'dbm' 파일을 GNU 'dbm' 으로 접근할 수 없습니다.*

  만일 여러분들이 오래된 데이터베이스를 GNU 'dbm' 으로 사용하려면, 이전에

  'conv2gdbm' 프로그램을 사용해야 합니다. ('conv2gdbm' 프로그램은 gdbm 소스

  배포본에 포함되어 있습니다.)

 

  또한, GNU 'dbm' 은 'ndbm' 과 호환되는 함수를 가지고 있습니다. ndbm 호환성

  함수를 사용하려면, 헤더파일 'ndbm.h' 를 포함해야 합니다.

 

  'ndbm' 과 마찬가지로, 모든 리턴된 datum 은 static 스토로지로 간주됩니다.

  따라서 여러분들은 메모리를 free 할 필요는 없으며, 'ndbm' 와 호환되는 함수

  들이 그러한 일을 대신할 것입니다.

 

  그 함수들은 다음과 같습니다.

 

    DBM *dbm_open(name, flags, mode);

    void dbm_close(file);

    datum dbm_fetch(file, key);

    int dbm_store(file, key, `content', flags);

    int dbm_delete(file, key);

    datum dbm_firstkey(file);

    datum dbm_nextkey(file);

    int dbm_error(file);

    int dbm_clearerr(file);

    int dbm_dirfno(file);

    int dbm_pagfno(file);

    int dbm_rdonly(file);

 

  만일, UNIX 'dbm' 이나 'ndbm' 을 사용한 오래된 C 프로그램을 컴파일해서

  'gdbm' 파일을 사용하기를 원한다면, 다음의 'cc' 명령어를 실행하세요.

 

    cc ... -L /usr/local/lib -lgdbm

 

  '-L/usr/local/lib' 는 여러분들이 'gdbm' 라이브러리를 가지고 있는 장소에

  따라 다를 수 있습니다.

 

 3) 'dbm' 파일을 'gdbm' 파일 포맷으로 변환하기

 

  'conv2gdbm' 프로그램은 'dbm' 데이터베이스를 'gdbm' 으로 변환합니다.

  사용법은 다음과 같습니다.

 

      conv2gdbm [-q] [-b block_size] dbm_file [gdbm_file]

 

  옵션은 다음과 같습니다.

 

  -q

    conv2gdbm 은 조용하게 작업을 수행하도록 합니다.

 

  block_size

    gdbm_open 의 block_size 와 같습니다.

 

  dbm_file

    '.pag' 나 '.dir' 확장자를 달지 않는 'dbm' 파일의 이름

 

  gdbm_file

    완전한 gdbm 파일의 이름입니다. 만일 지정하지 않았다면, gdbm 파일의 이름은

    dbm 파일이름에서 확장자를 뺀것을 기본으로 취합니다.

 

    conv2gdbm dbmfile

 

  이러한 사용예는 'dbmfile.pag' 나 'dbmfile.dir' 을 'gdbm' 파일인 'dbmfile'

  로 변환합니다.

 

 4) 버그 리포팅

 

  혹시 GNU 'dbm' 에 버그가 있다면, 신중하게 진짜 버그인지를 확인하시고, 버그

  리포팅에 관련된 문서를 읽어보시고 아래의 주소로 연락을 주십시요.

 

    Internet: `bug-gnu-utils@prep.ai.mit.edu'.

    UUCP: `mit-eddie!prep.ai.mit.edu!bug-gnu-utils'.

 

  혹시, 제의나 질문, 본래의 영문 info 파일에 버그가 있다던지 해서 제작자와

  접촉하시려면, 아래로 연락하십시요.

 

        e-mail:  phil@cs.wwu.edu

        us-mail:  Philip A. Nelson

                  Computer Science Department

                  Western Washington University

                  Bellingham, WA 98226

 

  또한, 메인테이너와 연락하시려면 아래로 연락하십시요.

 

        e-mail:  downsj@CSOS.ORST.EDU

 

Posted by stekilove
,