맞춤형 스토리지 엔진 작성 4

43543 단어
16.9.기본 테이블 스캔 기능 구현
16.9.1. 구현 storelock() 함수
16.9.2. external 구현lock() 함수
16.9.3. rnd 구현init() 함수
16.9.4. info() 함수 구현
16.9.5. extra() 함수 구현
16.9.6. rnd 구현next () 함수
가장 기본적인 저장 엔진은 시계만 읽고 스캔하는 기능을 실현할 수 있다.이런 종류의 엔진은 SQL 로그 조회와 MySQL 이외에 채워진 다른 데이터 파일을 지원하는 데 사용할 수 있다.
이 섹션에서는 고급 스토리지 엔진을 구축할 수 있는 토대를 제공합니다.
다음은 CSV 엔진의 9행 테이블 스캔 프로세스 중 수행된 메소드 호출입니다.
ha_tina::store_lock
ha_tina::external_lock
ha_tina::info
ha_tina::rnd_init
ha_tina::extra - ENUM HA_EXTRA_CACHE   Cache record in HA_rrnd()
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::rnd_next
ha_tina::extra - ENUM HA_EXTRA_NO_CACHE   End cacheing of records (def)
ha_tina::external_lock
ha_tina::extra - ENUM HA_EXTRA_RESET   Reset database to after open

16.9.1.구현 storelock() 함수
읽기 또는 쓰기 작업을 수행하기 전에 store 호출lock() 함수.
테이블 잠금 프로세서에 잠금을 추가하기 전에 (thr lock.c 참조) mysqld는 요청한 잠금으로 저장소 잠금을 호출합니다.현재 메모리 잠금은 쓰기 잠금을 읽기 잠금(또는 다른 잠금)으로 변경하거나 잠금을 무시하거나 (MySQL 잠금을 사용하지 않으려면) 많은 테이블에 잠금을 추가합니다(MERGE 프로세서를 사용할 때처럼).
예를 들어, Berkeley DB는 모든 WRITE 잠금을 TL 로 변경할 수 있습니다.WRITE_ALLOW_WRITE(WRITES를 실행 중이지만 다른 작업자는 계속 허용됨).
잠금을 해제하면 store 도 호출됩니다.lock (), 이 경우, 보통 아무것도 할 필요가 없습니다.
특정 상황에서 MySQL은 TLIGNORE 요청입니다.이것은 우리가 지난번과 같은 잠금을 요청하고 있음을 의미합니다. 이것도 무시되어야 합니다. (우리가 테이블의 일부분을 열었을 때 다른 사람이 테이블 리셋 작업을 실행하면 이 상황이 발생합니다. 이때 mysqld는 테이블을 닫고 다시 열고 지난번과 같은 잠금을 가져옵니다.)우리는 장래에 이 특성을 삭제할 계획이다.
가능한 잠금 유형은includes/thr 에 정의됩니다lock.h에서 다음을 나열합니다.
enum thr_lock_type
{
         TL_IGNORE=-1,
                    TL_UNLOCK,                             /* UNLOCK ANY LOCK */
                    TL_READ,                                 /* Read lock */
                    TL_READ_WITH_SHARED_LOCKS,  
         TL_READ_HIGH_PRIORITY,      /* High prior. than TL_WRITE. Allow concurrent insert */
         TL_READ_NO_INSERT,                /* READ, Don't allow concurrent insert */
         TL_WRITE_ALLOW_WRITE,                   /*   Write lock, but allow other threads to read / write. */
         TL_WRITE_ALLOW_READ,        /*       Write lock, but allow other threads to read / write. */
         TL_WRITE_CONCURRENT_INSERT, /* WRITE lock used by concurrent insert. */
         TL_WRITE_DELAYED,                 /* Write used by INSERT DELAYED.  Allows READ locks */
         TL_WRITE_LOW_PRIORITY,            /* WRITE lock that has lower priority than TL_READ */
         TL_WRITE,                         /* Normal WRITE lock */
         TL_WRITE_ONLY               /* Abort new lock request with an error */
};  

실제 잠금 처리는 잠금 실행에 따라 다르기 때문에 요청한 잠금 유형을 선택하거나 어떤 잠금 유형을 선택하지 않고 상황에 따라 적절하게 자신을 대입하는 방법을 선택할 수 있습니다.CSV 스토리지 엔진 구축 예는 다음과 같습니다.
THR_LOCK_DATA **ha_tina::store_lock(THD *thd,
                                     THR_LOCK_DATA **to,
                                     enum thr_lock_type lock_type)
 {
   if (lock_type != TL_IGNORE && lock.type == TL_UNLOCK)
     lock.type=lock_type;
   *to++= &lock;
   return to;
 }  

16.9.2.external 구현lock() 함수
external_lock () 함수는 트랜잭션 시작 시 호출되거나 LOCK TABLES 문을 보낼 때 호출되며 트랜잭션 저장소 엔진에 사용됩니다.
sql/hainnodb.cc와 sql/haberkeley.cc 파일에서 external 사용lock ()의 예이지만 대부분의 스토리지 엔진은 EXAMPLE 스토리지 엔진처럼 간단하게 0을 반환합니다.
int ha_example::external_lock(THD *thd, int lock_type)
 {
   DBUG_ENTER("ha_example::external_lock");
   DBUG_RETURN(0);
 }

16.9.3.rnd 구현init() 함수
모든 테이블 스캔 전에 호출된 함수는 rndinit() 함수.함수 rndinit () 는 시계 스캔을 준비하는 데 사용되며, 계수기와 바늘을 시계의 시작 상태로 복원합니다.
다음은 CSV 스토리지 엔진의 예입니다.
  int ha_tina::rnd_init(bool scan)
    {
      DBUG_ENTER("ha_tina::rnd_init");
 
      current_position= next_position= 0;
      records= 0;
      chain_ptr= chain;
 
      DBUG_RETURN(0);
    }  

16.9.4.info() 함수 구현
테이블 스캔을 실행하기 전에 info () 함수를 호출하여 최적화 프로그램에 추가 정보를 제공합니다.
최적화 프로그램에 필요한 정보는 반환값을 통해 정해진 것이 아닙니다. 저장 엔진 클래스의 특정한 속성을 채워야 합니다. info () 호출이 되돌아오면 최적화 프로그램은 저장 엔진 클래스를 읽을 것입니다.
최적화 프로그램 사용 외에도 info() 함수를 호출하는 동안 많은 값 집합이 SHOW TABLE STATUS 문에 사용됩니다.
sql/handler.h에는 일반적인 등록 정보와 함께 전체 공통 등록 정보가 나열됩니다.
ulonglong data_file_length;           /* Length off data file */
ulonglong max_data_file_length;       /* Length off data file */
ulonglong index_file_length;
ulonglong max_index_file_length;
ulonglong delete_length;              /* Free bytes */
ulonglong auto_increment_value;
ha_rows records;                      /* Records in table */
ha_rows deleted;                      /* Deleted records */
ulong raid_chunksize;
ulong mean_rec_length;         /* physical reclength */
time_t create_time;                   /* When table was created */
time_t check_time;
time_t update_time;  

테이블 스캔에 있어서 가장 중요한 속성은'records'로 테이블의 기록 수를 가리킨다.스토리지 엔진이 테이블에 0 또는 1 줄이 있음을 나타내거나 2 줄 이상이 있음을 나타내면 최적화 프로그램의 실행 방식이 다릅니다.따라서, 테이블 스캔을 실행하기 전에 테이블에 몇 줄이 있는지 알 수 없을 때, 2보다 큰 값을 되돌려야 한다. 이것은 매우 중요하다. (예를 들어 데이터는 외부에서 채워져 있다.)
16.9.5.extra() 함수 구현
어떤 조작을 실행하기 전에 extra () 함수를 호출해서 저장 엔진이 특정한 조작을 어떻게 실행하는지 알려 주어야 한다.
추가 호출에 대한 프롬프트는 강제적이지 않으며 대부분의 스토리지 엔진에서 0을 반환합니다.
int ha_tina::extra(enum ha_extra_function operation)
 {
   DBUG_ENTER("ha_tina::extra");
   DBUG_RETURN(0);
 }

16.9.6.rnd 구현next () 함수
테이블의 초기화 작업이 완료되면 MySQL 서버는 프로세서의 rnd 를 호출합니다next () 함수는 두 개의 스캐너마다 한 번씩 호출되며 서버의 검색 조건이 충족되거나 파일의 끝에 도달할 때까지 다음 상황에서 처리 프로그램은HA 로 되돌아옵니다ERR_END_OF_FILE.
rnd_next () 함수에는 *buf라는 단자 바이트 매개 변수가 있습니다.*buf 매개 변수의 경우 내부 MySQL 형식에 따라 테이블 행의 컨텐트로 채워야 합니다.
서버는 고정 길이 행, 가변 길이 행, BLOB 포인터가 있는 가변 길이 행 등 세 가지 데이터 형식을 사용합니다.각 형식에 대해 열은 CREATE TABLE 문에 의해 정의된 순서대로 표시됩니다(테이블 정의는.frm 파일에 저장되며 최적화 프로그램과 처리 프로그램은 모두 같은 원본, 즉 TABLE 구조, 테이블의 메타데이터에 접근할 수 있습니다).
각 형식은 열당 1비트의 NULL bitmap으로 시작합니다.6개의 열을 포함하는 테이블에는 비트맵이 1바이트이고 9~16열을 포함하는 테이블에는 비트맵이 2바이트로 추정된다.특정 값이 NULL임을 나타내려면 열 NULL 위치를 1로 설정해야 합니다.
NULL bitmap이 차례로 열에 들어가면 각 열에는 MySQL 매뉴얼의'MySQL 데이터 유형'섹션에 지정된 크기가 포함됩니다.서버에서 열의 데이터 형식은 sql/field에 정의됩니다.cc 파일에서고정된 길이의 줄 형식에 대해 열은 간단하게 하나씩 배치됩니다.가변 길이 행의 경우 VARCHAR 열은 1바이트 길이와 문자열로 인코딩됩니다.BLOB 열이 있는 가변 길이 줄에 대해 각 BLOB는 두 부분으로 표시한다. 먼저 BLOB의 실제 크기를 나타내는 정수를 표시하고 그 다음에 메모리에 있는 BLOB를 가리키는 바늘을 가리킨다.
모든 테이블 프로세서에서 rndnext () 를 시작하면 줄 변환 (또는 "포장") 의 예시를 찾을 수 있습니다.예를 들어, hatina.cc중,findcurrent_row () 내의 코드는 TABLE 구조 (테이블에서 가리키는) 와 문자열 대상 (이름 버퍼) 을 사용하여 문자 데이터 (CSV 파일에서 온) 를 포장하는 방법을 보여 줍니다.디스크에 줄을 다시 쓰기 위해서는 내부 형식에서 해제하는 역변환이 필요합니다.
다음은 CSV 스토리지 엔진의 예입니다.
int ha_tina::rnd_next(byte *buf)
 {
   DBUG_ENTER("ha_tina::rnd_next");
 
   statistic_increment(table->in_use->status_var.ha_read_rnd_next_count, &LOCK_status);
 
   current_position= next_position;
   if (!share->mapped_file)
     DBUG_RETURN(HA_ERR_END_OF_FILE);
   if (HA_ERR_END_OF_FILE == find_current_row(buf) )
     DBUG_RETURN(HA_ERR_END_OF_FILE);
 
   records++;
   DBUG_RETURN(0);
 }  

내부 줄 형식에서 CSV 줄 형식으로 변환하려면findcurrent_row () 함수에서 실행된 것입니다.
int ha_tina::find_current_row(byte *buf)
 {
   byte *mapped_ptr= (byte *)share->mapped_file + current_position;
   byte *end_ptr;
   DBUG_ENTER("ha_tina::find_current_row");
 
   /* EOF should be counted as new line */
   if ((end_ptr=  find_eoln(share->mapped_file, current_position,
                            share->file_stat.st_size)) == 0)
     DBUG_RETURN(HA_ERR_END_OF_FILE);
 
   for (Field **field=table->field ; *field ; field++)
   {
     buffer.length(0);
     mapped_ptr++; // Increment past the first quote
     for(;mapped_ptr != end_ptr; mapped_ptr++)
     {
       // Need to convert line feeds!
       if (*mapped_ptr == '"' &&
           (((mapped_ptr[1] == ',') && (mapped_ptr[2] == '"')) ||
            (mapped_ptr == end_ptr -1 )))
       {
         mapped_ptr += 2; // Move past the , and the "
         break;
       }
       if (*mapped_ptr == '\\' && mapped_ptr != (end_ptr - 1))
       {
         mapped_ptr++;
         if (*mapped_ptr == 'r')
           buffer.append('\r');
         else if (*mapped_ptr == 'n' )
           buffer.append('
');
         else if ((*mapped_ptr == '\\') || (*mapped_ptr == '"'))
           buffer.append(*mapped_ptr);
         else  /* This could only happed with an externally created file */
         {
           buffer.append('\\');
           buffer.append(*mapped_ptr);
         }
       }
       else
         buffer.append(*mapped_ptr);
     }
     (*field)->store(buffer.ptr(), buffer.length(), system_charset_info);
   }
   next_position= (end_ptr - share->mapped_file)+1;
   /* Maybe use \N for null? */
   memset(buf, 0, table->s->null_bytes); /* We do not implement nulls! */
 
   DBUG_RETURN(0);
 }  

좋은 웹페이지 즐겨찾기