Data-RoaringBitmap-Shared
view release on metacpan or search on metacpan
hdr->magic = RB_MAGIC;
hdr->version = RB_VERSION;
hdr->bitmap_id = rb_gen_bitmap_id(base);
hdr->container_cap = container_cap;
hdr->container_used = 1; /* slot 0 reserved as the NULL sentinel */
hdr->free_head = 0;
hdr->free_count = 0;
hdr->cardinality = 0;
hdr->total_size = total_size;
hdr->reader_slots_off = L.reader_slots;
hdr->bucket_table_off = L.bucket_table;
hdr->container_pool_off = L.container_pool;
__atomic_thread_fence(__ATOMIC_SEQ_CST);
}
static inline RbHandle *rb_setup(void *base, size_t map_size,
const char *path, int backing_fd) {
RbHeader *hdr = (RbHeader *)base;
RbHandle *h = (RbHandle *)calloc(1, sizeof(RbHandle));
if (!h) {
munmap(base, map_size);
if (backing_fd >= 0) close(backing_fd);
return NULL;
}
h->hdr = hdr;
h->base = base;
h->reader_slots = (RbReaderSlot *)((uint8_t *)base + hdr->reader_slots_off);
h->mmap_size = map_size;
h->path = path ? strdup(path) : NULL;
h->backing_fd = backing_fd;
h->my_slot_idx = UINT32_MAX;
return h;
}
/* Validate a mapped header (shared by rb_create reopen and rb_open_fd).
* Stored geometry wins on reopen. */
static inline int rb_validate_header(const RbHeader *hdr, uint64_t file_size) {
if (hdr->magic != RB_MAGIC) return 0;
if (hdr->version != RB_VERSION) return 0;
if (hdr->bitmap_id == 0) return 0; /* identity must have been set at create */
if (hdr->container_cap < 1 || hdr->container_cap > RB_MAX_CONTAINERS) return 0;
if (hdr->total_size != file_size) return 0;
if (hdr->total_size != rb_total_size(hdr->container_cap)) return 0;
RbLayout L = rb_layout();
if (hdr->reader_slots_off != L.reader_slots) return 0;
if (hdr->bucket_table_off != L.bucket_table) return 0;
if (hdr->container_pool_off != L.container_pool) return 0;
if (hdr->container_used < 1 || hdr->container_used > hdr->container_cap) return 0;
if (hdr->free_head >= hdr->container_cap) return 0;
if (hdr->free_count > hdr->container_cap) return 0;
return 1;
}
/* Securely obtain a fd: create exclusively (O_CREAT|O_EXCL|O_NOFOLLOW at
* file_mode, default 0600), or attach an existing file (O_RDWR|O_NOFOLLOW, no
* O_CREAT). Blocks a symlink swap or pre-seeded/hard-linked backing file;
* cross-user sharing is opt-in via a wider file_mode. */
static int rb_secure_open(const char *path, mode_t file_mode, char *errbuf) {
for (int attempt = 0; attempt < 100; attempt++) {
int fd = open(path, O_RDWR|O_CREAT|O_EXCL|O_NOFOLLOW|O_CLOEXEC, file_mode);
if (fd >= 0) { (void)fchmod(fd, file_mode); return fd; } /* exact mode: umask narrowed the O_EXCL create */
if (errno != EEXIST) { RB_ERR("create(%s): %s", path, strerror(errno)); return -1; }
fd = open(path, O_RDWR|O_NOFOLLOW|O_CLOEXEC);
if (fd >= 0) return fd;
if (errno == ENOENT) continue;
RB_ERR("open(%s): %s", path, strerror(errno));
return -1;
}
RB_ERR("open(%s): create/attach kept racing", path);
return -1;
}
static RbHandle *rb_create(const char *path, uint64_t container_cap_in, mode_t file_mode, char *errbuf) {
if (!rb_validate_create_args(container_cap_in, errbuf)) return NULL;
uint32_t container_cap = (uint32_t)container_cap_in;
uint64_t total = rb_total_size(container_cap);
int anonymous = (path == NULL);
int fd = -1;
size_t map_size;
void *base;
if (anonymous) {
map_size = (size_t)total;
base = mmap(NULL, map_size, PROT_READ|PROT_WRITE, MAP_SHARED|MAP_ANONYMOUS, -1, 0);
if (base == MAP_FAILED) { RB_ERR("mmap: %s", strerror(errno)); return NULL; }
} else {
fd = rb_secure_open(path, file_mode, errbuf);
if (fd < 0) return NULL;
if (flock(fd, LOCK_EX) < 0) { RB_ERR("flock: %s", strerror(errno)); close(fd); return NULL; }
struct stat st;
if (fstat(fd, &st) < 0) { RB_ERR("fstat: %s", strerror(errno)); flock(fd, LOCK_UN); close(fd); return NULL; }
int is_new = (st.st_size == 0);
if (!is_new && (uint64_t)st.st_size < sizeof(RbHeader)) {
RB_ERR("%s: file too small (%lld)", path, (long long)st.st_size);
flock(fd, LOCK_UN); close(fd); return NULL;
}
if (is_new && ftruncate(fd, (off_t)total) < 0) {
RB_ERR("ftruncate: %s", strerror(errno)); flock(fd, LOCK_UN); close(fd); return NULL;
}
map_size = is_new ? (size_t)total : (size_t)st.st_size;
base = mmap(NULL, map_size, PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
if (base == MAP_FAILED) { RB_ERR("mmap: %s", strerror(errno)); flock(fd, LOCK_UN); close(fd); return NULL; }
if (!is_new) {
if (!rb_validate_header((RbHeader *)base, (uint64_t)st.st_size)) {
RB_ERR("invalid roaring-bitmap file"); munmap(base, map_size); flock(fd, LOCK_UN); close(fd); return NULL;
}
flock(fd, LOCK_UN); close(fd);
return rb_setup(base, map_size, path, -1);
}
}
rb_init_header(base, container_cap, total);
if (fd >= 0) { flock(fd, LOCK_UN); close(fd); }
return rb_setup(base, map_size, path, -1);
}
static RbHandle *rb_create_memfd(const char *name, uint64_t container_cap_in, char *errbuf) {
if (!rb_validate_create_args(container_cap_in, errbuf)) return NULL;
uint32_t container_cap = (uint32_t)container_cap_in;
uint64_t total = rb_total_size(container_cap);
( run in 1.558 second using v1.01-cache-2.11-cpan-600a1bdf6e4 )