2014-03-26 9 views
1

저는 버클리 DB에서 레코드를 넘겨주기위한 반복자를 구현하고 있습니다. 그러나 커서를 호출하기 전에 DB_DBT_USERMEM 플래그를 설정해야합니다 DB_NEXT 함께 얻을.버클리 DB의 함수 포인터 반복자

이렇게하면 반복자의 응집력이 떨어지고 검색 할 각 데이터 유형에 대해 여러 개의 반복자를 구현해야합니다.

포인터가없는 구조와 기본 데이터 형식을 트래버스 할 수있는 일반 이터레이터를 사용할 수있는 방법이 있습니까? 여기 내가 성취하려고하는 것이있다.

#include <stdio.h> 
#include <string.h> 
#include <db.h> 

// let this function handle integers and use DB_DBT_USERMEM for memory alignment 
void integer_items(DBT key, DBT data) { 
     int number = 0; 
     data.data = &number; 
     data.flags = DB_DBT_USERMEM; 
     data.ulen = sizeof(int); 
     printf("key is: %s, data is: %d\n", (char *) key.data,number); 
} 

// let this function handle pointer structs. No need for DB_DBT_USERMEM 
void ptr_struct_items(DBT key, DBT data) { 
     // MY_STRUCT user; 
     // marshall struct... 
     // buffsize = sizeof(int) +(strlen(user.familiar_name) + strlen(user.surname) + 2); 
     // databuff = malloc(buffsize); 
     // memset(databuff, 0, buffsize); 
     // ... 
     // printf("key is: %s, data is: %d\n", (char *) key.data,number); 
} 

int iterator(DB *database, void(*function)(DBT key, DBT data)) { 
     DBT key, data; 
     DBC *cursor; 

     memset(&key, 0, sizeof(DBT)); 
     memset(&data, 0, sizeof(DBT)); 
     database->cursor(database, NULL, &cursor, 0); 
     while(cursor->c_get(cursor, &key, &data, DB_NEXT) == 0){ 
       (*function)(key, data); 
     } 
     cursor->c_close(cursor); 
     return 0; 
} 

int main() { 
     DB_ENV *myEnv; 
     DB *dbp; 
     DBT key, data; 
     int r, v = 10; 
     char *k = "Test"; 

     db_env_create(&myEnv, 0); 
     myEnv->open(myEnv, "./", DB_CREATE | DB_INIT_MPOOL, 0); 

     db_create(&dbp, myEnv, 0); 
     dbp->open(dbp, NULL, "test.db", NULL, DB_HASH, DB_CREATE, 0664); 

     memset(&key, 0, sizeof(key)); 
     memset(&data, 0, sizeof(data)); 

     key.data = k; 
     key.size = strlen(k) +1; 
     data.data = &v; 
     data.size = sizeof(int); 

     if((r=dbp->put(dbp, NULL, &key, &data, 0)!=0)) 
       fprintf(stderr, "%s\n", db_strerror(r)); 

     iterator(dbp, integer_items); 
     iterator(dbp, ptr_struct_items); 

     return 0; 
} 

답변

0

당신은 거의 항상 DB_DBT_MALLOC/realloc을 위해 BDB 내부에서) 경우에만의 malloc을 (피에, DB_DBT_USERMEM를 사용하고 싶습니다. 그것을 사용할 때 데이터베이스의 가장 큰 항목을 저장할만큼 충분히 큰 메모리를 전달해야합니다. DBT 키를 사용할 수도 있으므로 DBT 키도 마찬가지입니다.

예를 들어, 키와 데이터가 너무 작기 때문에 문자 배열을 "반복기"함수의 스택에 넣은 다음 memset()을 호출 한 후 키와 데이터를 초기화하십시오. 위의 내용은 c_get() 호출 후 USERMEM을 설정하기 때문에 잘못되었습니다.

다음은 키와 데이터에서 BDB 256 바이트가 작동하도록 수정 한 예제입니다.

void integer_items(DBT key, DBT data) { 
     int number = 0; 

     if (data.size == sizeof number) { 
      number = *(int *)data.data; 
      printf("key is: %s, data is: %d\n", (char *) key.data, number); 
     } 
} 

int iterator(DB *database, void(*function)(DBT key, DBT data)) { 
     DBT key, data; 
     DBC *cursor; 
     char kmem[256]; 
     char dmem[256]; 

     memset(&key, 0, sizeof(DBT)); 
     memset(&data, 0, sizeof(DBT)); 

     key.flags = DB_DBT_USERMEM; 
     key.data = kmem; 
     key.ulen = sizeof kmem; 

     data.flags = DB_DBT_USERMEM; 
     data.data = dmem; 
     data.ulen = sizeof dmem; 

     database->cursor(database, NULL, &cursor, 0); 
     while(cursor->c_get(cursor, &key, &data, DB_NEXT) == 0){ 
       (*function)(key, data); 
     } 
     cursor->c_close(cursor); 
     return 0; 
} 

반복기 내부의 다른 구조를 처리하려면 데이터 유형을 키의 일부로 포함하십시오. 예를 들어 키에 대한 정수 대신 struct를 사용하고 첫 번째 문자가 어떤 종류의 유형인지 정의하게하십시오. 그런 다음 이터레이터 함수에서 스위치를 켜면됩니다.

+0

답장을 보내 주셔서 감사합니다. 이터레이터가 포인터를 사용하여 구조체를 통과하고 기본 유형을 추적 할 수있는 방법이 있습니까? 예기치 않은 함수가 형식을 처리하도록 할 수 있습니까? 각 데이터 유형에 대한 다중 반복자와 반대입니다. 예제를 업데이트했습니다. –

+0

일반적인 처리 방법은 데이터 형식을 어떻게 든 키의 일부로 포함시키는 것입니다. 예를 들어 키에 대한 정수 대신 struct를 사용하고 첫 번째 문자가 어떤 종류의 유형인지 정의하게하십시오. 그런 다음 이터레이터 함수에서 스위치를 켜면됩니다. –

+0

고마워, 그게 내가 찾고있는 것 같습니다. –