Tôi đang phát triển một máy chủ cơ sở dữ liệu tương tự như Cassandra.
Sự phát triển đã được bắt đầu ở C, nhưng mọi thứ trở nên rất phức tạp nếu không có lớp học.
Hiện tại tôi đã chuyển mọi thứ trong C ++ 11, nhưng tôi vẫn đang học C ++ "hiện đại" và nghi ngờ về nhiều thứ.
Cơ sở dữ liệu sẽ hoạt động với các cặp Khóa / Giá trị. Mỗi cặp có thêm một số thông tin - khi nào cũng được tạo khi hết hạn (0 nếu không hết hạn). Mỗi cặp là bất biến.
Khóa là chuỗi C, Giá trị là void *, nhưng ít nhất là tại thời điểm tôi đang hoạt động với giá trị là chuỗi C.
Có IList
lớp trừu tượng . Nó được kế thừa từ ba lớp
VectorList
- Mảng động C - tương tự std :: vector, nhưng sử dụngrealloc
LinkList
- được thực hiện để kiểm tra và so sánh hiệu suấtSkipList
- lớp cuối cùng sẽ được sử dụng.
Trong tương lai tôi cũng có thể làm Red Black
cây.
Mỗi cái IList
chứa 0 hoặc nhiều con trỏ tới các cặp, được sắp xếp theo khóa.
Nếu IList
trở nên quá dài, nó có thể được lưu trên đĩa trong một tệp đặc biệt. Tập tin đặc biệt này là loại read only list
.
Nếu bạn cần tìm kiếm một khóa,
- đầu tiên trong bộ nhớ
IList
được tìm kiếm (SkipList
,SkipList
hoặcLinkList
). - Sau đó, tìm kiếm được gửi đến các tệp được sắp xếp theo ngày
(tệp mới nhất trước, tệp cũ nhất - cuối cùng).
Tất cả các tệp này là mmap-ed trong bộ nhớ. - Nếu không tìm thấy gì, thì không tìm thấy khóa.
Tôi không có nghi ngờ về việc thực hiện những IList
điều.
Những gì hiện đang làm tôi bối rối là sau:
Các cặp có kích thước khác nhau , chúng được phân bổ new()
và chúng đã std::shared_ptr
chỉ vào chúng.
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];
};
Biến thành viên "đệm" là biến có kích thước khác nhau. Nó lưu trữ khóa + giá trị.
Ví dụ: nếu khóa có 10 ký tự và giá trị là 10 byte khác, toàn bộ đối tượng sẽ là sizeof(Pair::Blob) + 20
(bộ đệm có kích thước ban đầu là 2, do hai byte kết thúc null)
Bố cục tương tự này cũng được sử dụng trên đĩa, vì vậy tôi có thể làm một cái gì đó như thế này:
// 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);
Tuy nhiên kích thước khác nhau này là một vấn đề ở nhiều nơi với mã C ++.
Ví dụ tôi không thể sử dụng std::make_shared()
. Điều này rất quan trọng đối với tôi, vì nếu tôi có 1M Cặp, tôi sẽ có phân bổ 2M.
Từ phía bên kia, nếu tôi thực hiện "bộ đệm" cho mảng động (ví dụ: char mới [123]), tôi sẽ mất "lừa" mmap, tôi sẽ thực hiện hai lần hủy bỏ nếu tôi muốn kiểm tra khóa và tôi sẽ thêm con trỏ - 8 byte cho lớp.
Tôi cũng đã cố gắng "kéo" tất cả các thành viên Pair::Blob
vào Pair
, vì vậy Pair::Blob
chỉ là bộ đệm, nhưng khi tôi kiểm tra nó, nó khá chậm, có lẽ là do sao chép dữ liệu đối tượng xung quanh.
Một thay đổi khác tôi cũng nghĩ là loại bỏ Pair
lớp và thay thế nó bằng std::shared_ptr
và "đẩy" tất cả các phương thức trở lại Pair::Blob
, nhưng điều này sẽ không giúp tôi với Pair::Blob
lớp kích thước thay đổi .
Tôi tự hỏi làm thế nào tôi có thể cải thiện thiết kế đối tượng để thân thiện hơn với C ++.
Mã nguồn đầy đủ có tại đây:
https://github.com/nmmmnu/HM3
IList::remove
hoặc khi IList bị hủy. Mất nhiều thời gian, nhưng tôi sẽ làm theo chủ đề riêng biệt. Nó sẽ dễ dàng bởi vì IList sẽ được std::unique_ptr<IList>
. vì vậy tôi sẽ có thể "chuyển đổi" nó với danh sách mới và giữ đối tượng cũ ở nơi tôi có thể gọi d-tor.
C string
và dữ liệu luôn là một số bộ đệm void *
hoặc char *
, vì vậy bạn có thể truyền mảng char. Bạn có thể tìm thấy tương tự trong redis
hoặc memcached
. Tại một số điểm tôi có thể quyết định sử dụng std::string
hoặc cố định mảng char cho khóa, nhưng gạch chân nó sẽ vẫn là chuỗi C.
std::map
haystd::unordered_map
? Tại sao các giá trị (liên quan đến khóa) một sốvoid*
? Bạn có thể sẽ cần phải tiêu diệt chúng tại một số điểm; làm thế nào khi? Tại sao bạn không sử dụng mẫu?