멤캐시드용 스토리지 엔진 직접 작성하기

풀타임으로 일하고 있습니다. 멤베이스를 사용하는 "엔진 인터페이스"에 추가하고 있습니다. 멤캐시드. API를 설계하고 문서를 작성한 사람으로서, 저는 누구를 모욕하지 않으면서도 더 많은(그리고 더 나은) 문서가 필요하다고 말할 수 있습니다. 이 블로그 글은 나만의 스토리지 엔진을 작성하는 방법에 대한 미니 튜토리얼의 첫 번째 글입니다. 서버의 파일에 모든 키를 저장하는 엔진을 구축하는 동안 엔진 인터페이스의 모든 측면을 다루려고 노력할 것입니다.

이 항목에서는 개발 환경을 설정하는 기본 단계와 엔진의 수명 주기에 대해 다룹니다.

개발 환경 설정

가장 쉽게 '실행'하는 방법은 엔진 인터페이스의 개발 브랜치를 설치하는 것입니다. 다음 명령을 실행하기만 하면 됩니다:

$ git 복제 git://github.com/trondn/memcached.git
$ CD 멤캐시드
$ git -b 엔진 오리진/엔진
$ ./config/autorun.sh
$ ./configure -prefix=/opt/memcached
$ 모두 설치
     

다음 명령을 실행하여 서버가 작동하는지 확인합니다:

$ /opt/memcached/bin/memcached -E default_engine.so &
$ 에코 버전 | nc localhost 11211
버전 1.3.3_433_g82fb476 ≶- 다른 출력 문자열이 나타날 수 있습니다....
$ fg
$ ctrl-C

파일 시스템 엔진 만들기

자동 설정을 사용하여 엔진을 빌드하고 싶을 수도 있지만 자동 설정을 설정하는 것은 이 튜토리얼의 범위를 벗어납니다. 그냥 다음을 사용하겠습니다. 메이크파일 대신

ROOT=/opt/memcached
INCLUDE=-I${ROOT}/include

#CC = gcc
#CFLAGS=-std=gnu99 -g -DNDEBUG -fno-strict-aliasing -Wall
# -지정된 프로토타입 -지정되지 않은 프로토타입 -지정되지 않은 선언
# -Wredundant-decls
# ${INCLUDE} -dhave_config_h
#LDFLAGS=공유

CC=cc
CFLAGS=-I${ROOT}/include -m64 -xldscope=hidden -mt -g
      -errfmt=error -errwarn -errshort=tags -KPIC
LDFLAGS=-G -z defs -m64 -mt

모두: .libs/fs_engine.so

설치: 모두
 ${CP} .libs/fs_engine.so ${ROOT}/lib

SRC = fs_engine.c
OBJS = ${SRC:%.c=.libs/%.o}

.libs/fs_engine.so: .libs $(OBJS)
 ${LINK.c} -o $@ ${OBJS}

.libs:; -@mkdir $@

.libs/%.o: %.c
 ${COMPILE.c} $< -o $@ clean: $(RM) .libs/fs_engine.so $(OBJS)      

저는 Solaris에서 대부분의 개발을 Sun Studio 컴파일러를 사용하여 하고 있지만, gcc를 사용하시는 분들을 위해 gcc에 대한 설정 섹션을 추가했습니다. 다음에 대한 줄을 주석 처리하기만 하면 됩니다. CC, CFLAGS 그리고 LDFLAGS 를 클릭하고 # 를 클릭하세요.

멤캐시가 스토리지 엔진을 활용하려면 먼저 모듈을 로드한 다음 엔진 인스턴스를 생성해야 합니다. 이때 -E 옵션을 추가하여 memcached가 로드할 모듈의 이름을 지정할 수 있습니다. 모듈이 로드되면 memcached는 다음과 같은 이름의 심볼을 찾습니다. create_instance 를 사용하여 멤캐시가 엔진과 통신하는 데 사용할 수 있는 핸들을 생성합니다. 이것이 우리가 만들어야 할 첫 번째 함수이며, 다음과 같은 서명을 가져야 합니다:

멤캐시드_공개_API
ENGINE_ERROR_CODE create_instance(uint64_t 인터페이스, GET_SERVER_API get_server_api, ENGINE_HANDLE **handle);
     

이 함수의 목적은 서버에 모듈에 대한 핸들을 제공하는 것이지만, 다음과 같이 해야 합니다. not 아직 엔진 초기화를 수행하지 않았습니다. 그 이유는 멤캐시드 서버가 당사가 제공하는 API 버전을 지원하지 않을 수 있기 때문입니다. 서버가 지원하는 "가장 높은" 인터페이스 버전을 엔진에 알려야 한다는 의도입니다. 인터페이스및 엔진 필수 를 통해 해당 인터페이스 중 하나에 대한 설명자를 반환합니다. handle. 엔진이 하지 마십시오. 반환해야 하는 인터페이스 중 하나를 지원해야 합니다. ENGINE_ENOTSUP.

이제 예제 엔진에 대한 엔진 설명자를 정의하고 다음에 대한 구현을 만들어 보겠습니다. create_instance:

구조체 fs_engine {
  ENGINE_HANDLE_V1 엔진;
  /* 이 구조는 나중에 확장할 예정입니다 */.
};

멤캐시드_공개_API
ENGINE_ERROR_CODE create_instance(uint64_t 인터페이스,
                                 GET_SERVER_API GET_SERVER_API,
                                 ENGINE_HANDLE **핸들) {
  /*
   * 서버의 인터페이스가 당사가 지원하는 인터페이스인지 확인합니다. 지금 바로
   * 인터페이스가 하나뿐이므로 모든 인터페이스를 허용합니다.
   * 거부 여부는 서버에 달려 있습니다... 여기에 테스트를 추가합니다.
   * 사진 보기...
   */
  if (인터페이스 == 0) {
     엔진_엔오츠업을 반환합니다;
  }

  /*
   * 엔진 설명자를 위한 메모리를 할당합니다. 저는
   * 전역 변수를 사용하면 나중에 문제가 발생할 수 있기 때문입니다.
   * 나중에 동일한 엔진의 인스턴스를 여러 개 만들기로 결정합니다.
   * 첫날부터 안전한 편에 서는 것이 좋습니다...
   */
  구조체 fs_engine *h = calloc(1, sizeof(*h));
  if (h == NULL) {
     엔진_이름을 반환합니다;
  }

  /*
   * 엔진 API의 첫 번째 버전을 구현할 예정입니다.
   * 멤캐시드 코어에 어떤 구조를 가져야 하는지 알려줘야 합니다.
   * 예상
   */
  h->engine.interface.interface = 1;

  /*
   * API 진입점을 이를 구현하는 함수에 매핑합니다.
   */
  h->engine.initialize = fs_initialize;
  h->engine.destroy = fs_destroy;

  /* 핸들을 코어로 다시 전달합니다 */.
  *핸들 = (ENGINE_HANDLE*)h;

  엔진_성공을 반환합니다;
}
     

에서 제공하는 인터페이스가 create_instance 가 멤캐시드에서 지원되는 인터페이스에서 삭제되면 코어는 destroy() 를 즉시 사용합니다. 멤캐시드 코어는 절대로 any 엔진에서 반환된 포인터는 destroy() 를 호출합니다.

이제 계속해서 destroy() 함수입니다. 구현을 살펴보면 create_instance 에 매핑된 것을 볼 수 있습니다. destroy() 라는 함수에 fs_destroy():

static void fs_destroy(ENGINE_HANDLE* handle) {
  /* 엔진 디스크립터에 할당된 메모리를 해제합니다 */.
  free(handle);
}
     

코어가 우리가 지정한 인터페이스를 구현하는 경우 코어는 initialize() 메서드를 호출합니다. 이 때 엔진에서 데이터베이스 연결, 뮤텍스 초기화 등 모든 종류의 초기화를 수행해야 합니다. 엔진의 초기화 함수는 반환된 인스턴스 당 한 번만 호출됩니다. create_instance (멤캐시드 코어가 여러 스레드를 사용하는 경우에도). 코어는 not 초기화 메서드가 반환되기 전에 API의 다른 함수를 호출할 수 없습니다.

현재로서는 어떤 종류의 초기화도 필요하지 않으므로 다음 초기화 코드를 사용할 수 있습니다:

static ENGINE_ERROR_CODE fs_initialize(ENGINE_HANDLE* handle,
                                      const char* config_str) {
  엔진_성공을 반환합니다;
}
     

엔진이 다음 이외의 다른 것을 반환하는 경우 ENGINE_SUCCESS로 설정하면 멤캐시드 코어가 엔진 사용을 거부하고 destroy()

다음 블로그 글에서는 엔진을 로드하고 클라이언트의 명령을 처리할 수 있도록 기능을 추가해 보겠습니다.

 
이 문서 공유하기
받은 편지함에서 카우치베이스 블로그 업데이트 받기
이 필드는 필수 입력 사항입니다.

작성자

게시자 트론드 노비, 선임 개발자, Couchbase

트론드 노비는 카우치베이스의 소프트웨어 아키텍트입니다. Couchbase 및 Memcached 프로젝트의 핵심 기여자입니다. C/C++ 및 node.js Couchbase 클라이언트 라이브러리를 만들었습니다.

댓글 남기기

카우치베이스 카펠라를 시작할 준비가 되셨나요?

구축 시작

개발자 포털에서 NoSQL을 살펴보고, 리소스를 찾아보고, 튜토리얼을 시작하세요.

카펠라 무료 사용

클릭 몇 번으로 Couchbase를 직접 체험해 보세요. Capella DBaaS는 가장 쉽고 빠르게 시작할 수 있는 방법입니다.

연락하기

카우치베이스 제품에 대해 자세히 알고 싶으신가요? 저희가 도와드리겠습니다.