Я розробляю сервер баз даних, схожий на Cassandra.
Розробка була розпочата в С, але все стало дуже складним без занять.
Наразі я все портував на C ++ 11, але я все ще навчаюсь "сучасного" C ++ і маю сумніви щодо багатьох речей.
База даних буде працювати з парами ключ / значення. Кожна пара має додаткову інформацію - коли створюється також, коли вона закінчується (0, якщо не закінчується). Кожна пара незмінна.
Ключ - це рядок C, значення - недійсне *, але принаймні на даний момент я оперую зі значенням також як рядок C.
Є абстрактний IList
клас. Він успадковується від трьох класів
VectorList
- C динамічний масив - схожий на std :: vector, але використовуєrealloc
LinkList
- зроблено для перевірок та порівняння ефективностіSkipList
- клас, який нарешті буде використаний.
У майбутньому я можу зробити і Red Black
дерево.
Кожен IList
містить нуль або більше вказівників на пари, відсортовані за клавішами.
Якщо він 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, через два нульові закінчувальні байти)
Цей же макет використовується і на диску, тому я можу зробити щось подібне:
// 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()
. Це важливо для мене, тому що якби я мав пари 1М, я мав би виділення 2М.
З іншого боку, якщо я виконаю "буфер" для динамічного масиву (наприклад, новий 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. Це займає багато часу, але я збираюся робити це окремо. Це буде легко, тому що IList все std::unique_ptr<IList>
одно буде . тож я зможу "переключити" його з новим списком і зберегти старий об'єкт десь, де я можу викликати d-tor.
C string
а дані - це завжди якийсь буфер void *
або char *
, тож ви можете передавати масив char. Ви можете знайти подібні в redis
або memcached
. У якийсь момент я міг вирішити використовувати std::string
або виправлений масив char для ключа, але підкреслити це буде все-таки рядок C.
std::map
абоstd::unordered_map
? Чому значення (пов'язані з ключами) деякіvoid*
? Вам, певно, потрібно було б знищити їх у якийсь момент; як і коли? Чому ви не використовуєте шаблони?