我最终实现了一个我正在寻找的解决方案,它执行以下操作:
键值对以二进制格式存储在文件中,4 个字节为键,4 个字节为值。
该文件仅包含键值对,因此该文件只是一个键值对流,没有分隔符或多余的绒毛。
读写程序都可以在log(n)时间内搜索一个key并获取对应的值。这是通过将二进制文件重新解释为 8 字节块的数组,将每个 8 字节块重新解释为两个 4 字节块(键和值),并对映射文件执行二进制搜索来实现的。
我想出的代码如下:
struct Pair { uint32_t index[]; };
struct PairArray { uint64_t index[]; };
size_t getFilesize(const char* filename) {
struct stat st;
stat(filename, &st);
return st.st_size;
}
void binarySearch(const PairArray* const pairArray,
uint16_t numElements, uint32_t key, uint32_t*& value) {
int mid = numElements/2;
if (numElements == 0) return;
// interpret the pair as an array of 4 byte key and value
const Pair* pair = reinterpret_cast<const Pair*>(&(pairArray->index[mid]));
// new pointer to pass into recursive call
const PairArray* const newPairArray = reinterpret_cast<const PairArray* const>(
&(pairArray->index[mid + 1]));
// if key is found, point pointer passed by reference to value
if (key == pair->index[0]) {
value = const_cast<uint32_t*>(&pair->index[1]);
return;
}
// if search key is less than current key, binary search on left subarray
else if (key < pair->index[0]) {
binarySearch(pairArray, mid, key, value);
}
// otherwise, binary search on right subarray
else (numElements%2 == 0)
? binarySearch(newPairArray, mid - 1, key, value)
: binarySearch(newPairArray, mid, key, value);
}
int main(int argc, char** argv) {
...
// get size of the file
size_t filesize = getFilesize(argv[1]);
// open file
int fd = open(argv[1], O_RDWR, 0);
if (fd < 0) {
std::cerr << "error: file could not be opened" << std::endl;
exit(EXIT_FAILURE);
}
// execute mmap:
char* mmappedData = static_cast<char*>(
mmap(NULL, filesize, PROT_WRITE|PROT_READ, MAP_SHARED, fd, 0));
if (mmappedData == NULL) {
std::cerr << "error: could not memory map file" << std::endl;
exit(EXIT_FAILURE);
}
// interpret the memory mapped file as an array of 8 byte pairs
const PairArray* const pairArray = reinterpret_cast<PairArray*>(mmappedData);
// spin until file is unlocked, and take lock for yourself
while(true) {
int gotLock = flock(fd, LOCK_SH);
if (gotLock == 0) break;
}
// binary search for key value pair
uint32_t* value = nullptr;
binarySearch(pairArray, filesize/8, key, value);
(value == nullptr)
? std::cout << "null" << std::endl
: std::cout << *value << std::endl;
// release lock
flock(fd, LOCK_UN);
...
}