Cassandra와 비슷한 데이터베이스 서버를 개발 중입니다.
C로 개발이 시작되었지만 클래스 없이는 상황이 매우 복잡해졌습니다.
현재 C ++ 11로 모든 것을 이식했지만 여전히 "현대"C ++를 배우고 있으며 많은 것들에 대해 의문이 있습니다.
데이터베이스는 키 / 값 쌍으로 작동합니다. 모든 쌍에는 추가 정보가 있습니다. 만기 시점 (만료되지 않은 경우 0). 각 쌍은 변경할 수 없습니다.
키는 C 문자열이고 값은 void *이지만 적어도 C 문자열과 같은 값으로 작동하는 순간은 아닙니다.
추상 IList
클래스가 있습니다. 세 클래스에서 상속
VectorList
-C 동적 배열-std :: vector와 유사하지만realloc
LinkList
-점검 및 성능 비교를 위해 제작SkipList
-마침내 사용될 클래스.
앞으로 나는 Red Black
나무도 할 수 있습니다.
각각 IList
은 키로 정렬 된 0 개 이상의 쌍에 대한 포인터 를 포함합니다 .
경우 IList
너무 오래되었고, 그것은 특별한 파일의 디스크에 저장할 수 있습니다. 이 특수 파일은 일종입니다 read only list
.
키를 검색해야하는 경우
- 메모리에서 첫 번째
IList
가 검색됩니다 (SkipList
,SkipList
또는LinkList
). - 그런 다음 날짜별로 정렬 된
파일 (최신 파일부터 가장 오래된 파일-마지막)로 검색을 보냅니다 .
이 파일들은 모두 메모리에 저장되어 있습니다. - 아무것도 찾지 못하면 키를 찾을 수 없습니다.
나는 IList
물건 의 구현에 대해 의심의 여지가 없습니다 .
현재 나를 괴롭히는 것은 다음과 같습니다.
쌍은 함께있는 다른 크기, 그들에 의해 할당 new()
하고 그들이 가지고있는 std::shared_ptr
그들에게 지적했다.
class Pair{
public:
// several methods...
private:
struct Blob;
std::shared_ptr<const Blob> _blob;
};
struct Pair::Blob{
uint64_t created;
uint32_t expires;
uint32_t vallen;
uint16_t keylen;
uint8_t checksum;
char buffer[2];
};
"버퍼"멤버 변수는 크기가 다른 변수입니다. 키 + 값을 저장합니다.
예를 들어, 키가 10 자이고 값이 10 바이트 인 경우 전체 객체가됩니다 sizeof(Pair::Blob) + 20
(버퍼는 2 개의 널 종료 바이트로 인해 초기 크기가 2 임).
동일한 레이아웃이 디스크에서도 사용되므로 다음과 같이 할 수 있습니다.
// get the blob
Pair::Blob *blob = (Pair::Blob *) & mmaped_array[pos];
// create the pair, true makes std::shared_ptr not to delete the memory,
// since it does not own it.
Pair p = Pair(blob, true);
// however if I want the Pair to own the memory,
// I can copy it, but this is slower operation.
Pair p2 = Pair(blob);
그러나이 다른 크기는 C ++ 코드가있는 많은 장소에서 문제가됩니다.
예를 들어 나는 사용할 수 없습니다 std::make_shared()
. 1M 쌍이 있으면 2M 할당이 있기 때문에 이것은 나에게 중요합니다.
다른 쪽에서 동적 배열 (예 : 새로운 char [123])에 "버퍼"를 수행하면 mmap "트릭"을 잃게됩니다. 키를 확인하려면 두 가지 역 참조를해야하며 단일 포인터를 추가합니다 -클래스에 8 바이트
또한 "풀"모든 회원들에게 노력 Pair::Blob
에 Pair
그래서, Pair::Blob
그냥 버퍼로,하지만 난 그것을 테스트 할 때, 아마 때문에 주위의 객체 데이터를 복사하는 매우 느렸다.
내가 생각하고있는 또 다른 변화는 Pair
클래스 를 제거하고 클래스를 바꾸고 std::shared_ptr
모든 메소드를 다시 "푸시"하는 Pair::Blob
것입니다. 그러나 이것은 가변 크기 Pair::Blob
클래스에 도움이되지 않습니다 .
더 C ++ 친화적으로 만들기 위해 객체 디자인을 어떻게 개선 할 수 있는지 궁금합니다.
전체 소스 코드는 다음과 같습니다.
https://github.com/nmmmnu/HM3
IList::remove
있거나 IList가 파괴 될 때 수행됩니다 . 시간이 많이 걸리지 만 별도의 스레드로 수행하려고합니다. std::unique_ptr<IList>
어쨌든 IList가 있기 때문에 쉬울 것 입니다. 새 목록으로 "전환"하고 d-tor라고 부를 수있는 어딘가에 오래된 개체를 유지할 수 있습니다.
C string
있고 데이터는 항상 일부 버퍼 void *
또는 char *
이므로 char 배열을 전달할 수 있으므로 여기에서 가장 좋은 해결책은 아닙니다 . redis
또는 에서 비슷한 것을 찾을 수 있습니다 memcached
. 어떤 시점 std::string
에서 키에 고정 문자 배열 을 사용 하거나 고정 하기로 결정할 수 있지만 밑줄은 여전히 C 문자열입니다.
std::map
나std::unordered_map
? 값 (키와 연관된)이 왜void*
어떤가요? 언젠가는 그것들을 파괴해야 할 것입니다. 어떻게 그리고 언제? 왜 템플릿을 사용하지 않습니까?