mirror of
https://github.com/isar/libmdbx.git
synced 2024-10-30 11:29:19 +08:00
mdbx: add to env_copy() support for pipe/socket.
Change-Id: Ib2fc0249b494b885f28265f877de9953f089b403
This commit is contained in:
parent
b19e180fab
commit
0d4092f4ea
@ -11743,6 +11743,8 @@ int mdbx_put(MDBX_txn *txn, MDBX_dbi dbi, MDBX_val *key, MDBX_val *data,
|
||||
return rc;
|
||||
}
|
||||
|
||||
/**** COPYING *****************************************************************/
|
||||
|
||||
#ifndef MDBX_WBUF
|
||||
#define MDBX_WBUF ((size_t)1024 * 1024)
|
||||
#endif
|
||||
@ -11772,7 +11774,6 @@ static THREAD_RESULT __cold THREAD_CALL mdbx_env_copythr(void *arg) {
|
||||
uint8_t *ptr;
|
||||
int toggle = 0;
|
||||
int rc;
|
||||
size_t offset = pgno2bytes(my->mc_env, NUM_METAS);
|
||||
|
||||
mdbx_condmutex_lock(&my->mc_condmutex);
|
||||
while (!my->mc_error) {
|
||||
@ -11784,12 +11785,11 @@ static THREAD_RESULT __cold THREAD_CALL mdbx_env_copythr(void *arg) {
|
||||
ptr = my->mc_wbuf[toggle];
|
||||
again:
|
||||
if (wsize > 0 && !my->mc_error) {
|
||||
rc = mdbx_pwrite(my->mc_fd, ptr, wsize, offset);
|
||||
rc = mdbx_write(my->mc_fd, ptr, wsize);
|
||||
if (rc != MDBX_SUCCESS) {
|
||||
my->mc_error = rc;
|
||||
break;
|
||||
}
|
||||
offset += wsize;
|
||||
}
|
||||
|
||||
/* If there's an overflow page tail, write it too */
|
||||
@ -11984,9 +11984,42 @@ done:
|
||||
return rc;
|
||||
}
|
||||
|
||||
static void compact_fixup_meta(MDBX_env *env, MDBX_page *meta) {
|
||||
/* Calculate filesize taking in account shrink/growing thresholds */
|
||||
if (meta->mp_meta.mm_geo.next > meta->mp_meta.mm_geo.now) {
|
||||
const pgno_t aligned =
|
||||
pgno_align2os_pgno(env, pgno_add(meta->mp_meta.mm_geo.next,
|
||||
meta->mp_meta.mm_geo.grow -
|
||||
meta->mp_meta.mm_geo.next %
|
||||
meta->mp_meta.mm_geo.grow));
|
||||
meta->mp_meta.mm_geo.now = aligned;
|
||||
} else if (meta->mp_meta.mm_geo.next < meta->mp_meta.mm_geo.now) {
|
||||
meta->mp_meta.mm_geo.now = meta->mp_meta.mm_geo.next;
|
||||
const pgno_t aligner = meta->mp_meta.mm_geo.grow
|
||||
? meta->mp_meta.mm_geo.grow
|
||||
: meta->mp_meta.mm_geo.shrink;
|
||||
const pgno_t aligned =
|
||||
pgno_align2os_pgno(env, meta->mp_meta.mm_geo.next + aligner -
|
||||
meta->mp_meta.mm_geo.next % aligner);
|
||||
meta->mp_meta.mm_geo.now = aligned;
|
||||
}
|
||||
|
||||
if (meta->mp_meta.mm_geo.now < meta->mp_meta.mm_geo.lower)
|
||||
meta->mp_meta.mm_geo.now = meta->mp_meta.mm_geo.lower;
|
||||
if (meta->mp_meta.mm_geo.now > meta->mp_meta.mm_geo.upper)
|
||||
meta->mp_meta.mm_geo.now = meta->mp_meta.mm_geo.upper;
|
||||
|
||||
/* Update signature */
|
||||
assert(meta->mp_meta.mm_geo.now >= meta->mp_meta.mm_geo.next);
|
||||
meta->mp_meta.mm_datasync_sign = mdbx_meta_sign(&meta->mp_meta);
|
||||
}
|
||||
|
||||
/* Copy environment with compaction. */
|
||||
static int __cold mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn,
|
||||
mdbx_filehandle_t fd, uint8_t *buffer) {
|
||||
mdbx_filehandle_t fd, uint8_t *buffer,
|
||||
const bool dest_is_pipe) {
|
||||
const size_t meta_bytes = pgno2bytes(env, NUM_METAS);
|
||||
uint8_t *const data_buffer = buffer + meta_bytes;
|
||||
MDBX_page *const meta = mdbx_init_metas(env, buffer);
|
||||
/* copy canary sequenses if present */
|
||||
if (read_txn->mt_canary.v) {
|
||||
@ -12001,6 +12034,12 @@ static int __cold mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn,
|
||||
* fix any breakage like page leaks from ITS#8174. */
|
||||
meta->mp_meta.mm_dbs[MAIN_DBI].md_flags =
|
||||
read_txn->mt_dbs[MAIN_DBI].md_flags;
|
||||
compact_fixup_meta(env, meta);
|
||||
if (dest_is_pipe) {
|
||||
int rc = mdbx_write(fd, buffer, meta_bytes);
|
||||
if (rc != MDBX_SUCCESS)
|
||||
return rc;
|
||||
}
|
||||
} else {
|
||||
/* Count free pages + GC pages. Subtract from last_pg
|
||||
* to find the new last_pg, which also becomes the new root. */
|
||||
@ -12031,9 +12070,9 @@ static int __cold mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn,
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
ctx.mc_wbuf[0] = buffer + pgno2bytes(env, NUM_METAS);
|
||||
memset(ctx.mc_wbuf[0], 0, MDBX_WBUF * 2);
|
||||
ctx.mc_wbuf[1] = ctx.mc_wbuf[0] + MDBX_WBUF;
|
||||
memset(data_buffer, 0, MDBX_WBUF * 2);
|
||||
ctx.mc_wbuf[0] = data_buffer;
|
||||
ctx.mc_wbuf[1] = data_buffer + MDBX_WBUF;
|
||||
ctx.mc_next_pgno = NUM_METAS;
|
||||
ctx.mc_env = env;
|
||||
ctx.mc_fd = fd;
|
||||
@ -12042,7 +12081,12 @@ static int __cold mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn,
|
||||
mdbx_thread_t thread;
|
||||
int thread_err = mdbx_thread_create(&thread, mdbx_env_copythr, &ctx);
|
||||
if (likely(thread_err == MDBX_SUCCESS)) {
|
||||
rc = mdbx_env_cwalk(&ctx, &root, 0);
|
||||
if (dest_is_pipe) {
|
||||
compact_fixup_meta(env, meta);
|
||||
rc = mdbx_write(fd, buffer, meta_bytes);
|
||||
}
|
||||
if (rc == MDBX_SUCCESS)
|
||||
rc = mdbx_env_cwalk(&ctx, &root, 0);
|
||||
mdbx_env_cthr_toggle(&ctx, 1 | MDBX_EOF);
|
||||
thread_err = mdbx_thread_join(thread);
|
||||
mdbx_condmutex_destroy(&ctx.mc_condmutex);
|
||||
@ -12054,59 +12098,58 @@ static int __cold mdbx_env_compact(MDBX_env *env, MDBX_txn *read_txn,
|
||||
if (unlikely(ctx.mc_error != MDBX_SUCCESS))
|
||||
return ctx.mc_error;
|
||||
|
||||
if (root > new_root) {
|
||||
mdbx_error("post-compactification root %" PRIaPGNO
|
||||
" GT expected %" PRIaPGNO " (source DB corrupted)",
|
||||
root, new_root);
|
||||
return MDBX_CORRUPTED; /* page leak or corrupt DB */
|
||||
}
|
||||
if (root < new_root) {
|
||||
mdbx_notice("post-compactification root %" PRIaPGNO
|
||||
" LT expected %" PRIaPGNO " (page leak(s) in source DB)",
|
||||
root, new_root);
|
||||
/* fixup meta */
|
||||
meta->mp_meta.mm_dbs[MAIN_DBI].md_root = root;
|
||||
meta->mp_meta.mm_geo.next = root + 1;
|
||||
if (dest_is_pipe) {
|
||||
if (root != new_root) {
|
||||
mdbx_error("post-compactification root %" PRIaPGNO
|
||||
" NE expected %" PRIaPGNO
|
||||
" (source DB corrupted or has a page leak(s))",
|
||||
root, new_root);
|
||||
return MDBX_CORRUPTED; /* page leak or corrupt DB */
|
||||
}
|
||||
} else {
|
||||
if (root > new_root) {
|
||||
mdbx_error("post-compactification root %" PRIaPGNO
|
||||
" GT expected %" PRIaPGNO " (source DB corrupted)",
|
||||
root, new_root);
|
||||
return MDBX_CORRUPTED; /* page leak or corrupt DB */
|
||||
}
|
||||
if (root < new_root) {
|
||||
mdbx_notice("post-compactification root %" PRIaPGNO
|
||||
" LT expected %" PRIaPGNO " (page leak(s) in source DB)",
|
||||
root, new_root);
|
||||
/* fixup meta */
|
||||
meta->mp_meta.mm_dbs[MAIN_DBI].md_root = root;
|
||||
meta->mp_meta.mm_geo.next = root + 1;
|
||||
}
|
||||
compact_fixup_meta(env, meta);
|
||||
}
|
||||
}
|
||||
|
||||
/* Calculate filesize taking in account shrink/growing thresholds */
|
||||
if (meta->mp_meta.mm_geo.next > meta->mp_meta.mm_geo.now) {
|
||||
const pgno_t aligned =
|
||||
pgno_align2os_pgno(env, pgno_add(meta->mp_meta.mm_geo.next,
|
||||
meta->mp_meta.mm_geo.grow -
|
||||
meta->mp_meta.mm_geo.next %
|
||||
meta->mp_meta.mm_geo.grow));
|
||||
meta->mp_meta.mm_geo.now = aligned;
|
||||
} else if (meta->mp_meta.mm_geo.next < meta->mp_meta.mm_geo.now) {
|
||||
meta->mp_meta.mm_geo.now = meta->mp_meta.mm_geo.next;
|
||||
const pgno_t aligner = meta->mp_meta.mm_geo.grow
|
||||
? meta->mp_meta.mm_geo.grow
|
||||
: meta->mp_meta.mm_geo.shrink;
|
||||
const pgno_t aligned =
|
||||
pgno_align2os_pgno(env, meta->mp_meta.mm_geo.next + aligner -
|
||||
meta->mp_meta.mm_geo.next % aligner);
|
||||
meta->mp_meta.mm_geo.now = aligned;
|
||||
}
|
||||
|
||||
if (meta->mp_meta.mm_geo.now < meta->mp_meta.mm_geo.lower)
|
||||
meta->mp_meta.mm_geo.now = meta->mp_meta.mm_geo.lower;
|
||||
if (meta->mp_meta.mm_geo.now > meta->mp_meta.mm_geo.upper)
|
||||
meta->mp_meta.mm_geo.now = meta->mp_meta.mm_geo.upper;
|
||||
|
||||
/* Update signature */
|
||||
assert(meta->mp_meta.mm_geo.now >= meta->mp_meta.mm_geo.next);
|
||||
meta->mp_meta.mm_datasync_sign = mdbx_meta_sign(&meta->mp_meta);
|
||||
|
||||
/* Extend file if required */
|
||||
return (meta->mp_meta.mm_geo.now != meta->mp_meta.mm_geo.next)
|
||||
? mdbx_ftruncate(fd, pgno2bytes(env, meta->mp_meta.mm_geo.now))
|
||||
: MDBX_SUCCESS;
|
||||
if (meta->mp_meta.mm_geo.now != meta->mp_meta.mm_geo.next) {
|
||||
const size_t whole_size = pgno2bytes(env, meta->mp_meta.mm_geo.now);
|
||||
if (!dest_is_pipe)
|
||||
return mdbx_ftruncate(fd, whole_size);
|
||||
|
||||
const size_t used_size = pgno2bytes(env, meta->mp_meta.mm_geo.next);
|
||||
memset(data_buffer, 0, MDBX_WBUF);
|
||||
for (size_t offset = used_size; offset < whole_size;) {
|
||||
const size_t chunk =
|
||||
(MDBX_WBUF < whole_size - offset) ? MDBX_WBUF : whole_size - offset;
|
||||
/* copy to avoit EFAULT in case swapped-out */
|
||||
int rc = mdbx_write(fd, data_buffer, chunk);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
offset += chunk;
|
||||
}
|
||||
}
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
/* Copy environment as-is. */
|
||||
static int __cold mdbx_env_copy_asis(MDBX_env *env, MDBX_txn *read_txn,
|
||||
mdbx_filehandle_t fd, uint8_t *buffer) {
|
||||
mdbx_filehandle_t fd, uint8_t *buffer,
|
||||
const bool dest_is_pipe) {
|
||||
/* We must start the actual read txn after blocking writers */
|
||||
int rc = mdbx_txn_end(read_txn, MDBX_END_RESET_TMP);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
@ -12135,35 +12178,67 @@ static int __cold mdbx_env_copy_asis(MDBX_env *env, MDBX_txn *read_txn,
|
||||
mdbx_txn_unlock(env);
|
||||
|
||||
/* Copy the data */
|
||||
const uint64_t whole_size =
|
||||
const size_t whole_size =
|
||||
mdbx_roundup2(pgno2bytes(env, read_txn->mt_end_pgno), env->me_os_psize);
|
||||
const size_t used_size = pgno2bytes(env, read_txn->mt_next_pgno);
|
||||
mdbx_jitter4testing(false);
|
||||
|
||||
if (dest_is_pipe)
|
||||
rc = mdbx_write(fd, buffer, meta_bytes);
|
||||
|
||||
uint8_t *const data_buffer = buffer + meta_bytes;
|
||||
for (size_t offset = meta_bytes; rc == MDBX_SUCCESS && offset < used_size;) {
|
||||
if (dest_is_pipe) {
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
off_t in_offset = offset;
|
||||
const intptr_t written =
|
||||
sendfile(fd, env->me_fd, &in_offset, used_size - offset);
|
||||
if (unlikely(written <= 0)) {
|
||||
rc = written ? errno : MDBX_ENODATA;
|
||||
break;
|
||||
}
|
||||
offset = in_offset;
|
||||
continue;
|
||||
#endif
|
||||
} else {
|
||||
#if __GLIBC_PREREQ(2, 27) && defined(_GNU_SOURCE)
|
||||
for (off_t in_offset = meta_bytes; in_offset < (off_t)used_size;) {
|
||||
off_t out_offset = in_offset;
|
||||
ssize_t bytes_copied = copy_file_range(
|
||||
env->me_fd, &in_offset, fd, &out_offset, used_size - in_offset, 0);
|
||||
if (unlikely(bytes_copied <= 0)) {
|
||||
rc = bytes_copied ? errno : MDBX_ENODATA;
|
||||
break;
|
||||
off_t in_offset = offset, out_offset = offset;
|
||||
ssize_t bytes_copied = copy_file_range(
|
||||
env->me_fd, &in_offset, fd, &out_offset, used_size - offset, 0);
|
||||
if (unlikely(bytes_copied <= 0)) {
|
||||
rc = bytes_copied ? errno : MDBX_ENODATA;
|
||||
break;
|
||||
}
|
||||
offset = in_offset;
|
||||
continue;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
#else
|
||||
uint8_t *data_buffer = buffer + meta_bytes;
|
||||
for (size_t offset = meta_bytes; offset < used_size;) {
|
||||
|
||||
/* fallback to portable */
|
||||
const size_t chunk =
|
||||
(MDBX_WBUF < used_size - offset) ? MDBX_WBUF : used_size - offset;
|
||||
/* copy to avoit EFAULT in case swapped-out */
|
||||
memcpy(data_buffer, env->me_map + offset, chunk);
|
||||
rc = mdbx_pwrite(fd, data_buffer, chunk, offset);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
break;
|
||||
rc = mdbx_write(fd, data_buffer, chunk);
|
||||
offset += chunk;
|
||||
}
|
||||
#endif
|
||||
|
||||
if (likely(rc == MDBX_SUCCESS) && whole_size != used_size)
|
||||
rc = mdbx_ftruncate(fd, whole_size);
|
||||
/* Extend file if required */
|
||||
if (likely(rc == MDBX_SUCCESS) && whole_size != used_size) {
|
||||
if (!dest_is_pipe)
|
||||
rc = mdbx_ftruncate(fd, whole_size);
|
||||
else {
|
||||
memset(data_buffer, 0, MDBX_WBUF);
|
||||
for (size_t offset = used_size;
|
||||
rc == MDBX_SUCCESS && offset < whole_size;) {
|
||||
const size_t chunk =
|
||||
(MDBX_WBUF < whole_size - offset) ? MDBX_WBUF : whole_size - offset;
|
||||
/* copy to avoit EFAULT in case swapped-out */
|
||||
rc = mdbx_write(fd, data_buffer, chunk);
|
||||
offset += chunk;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
@ -12176,49 +12251,60 @@ int __cold mdbx_env_copy2fd(MDBX_env *env, mdbx_filehandle_t fd,
|
||||
if (unlikely(env->me_signature != MDBX_ME_SIGNATURE))
|
||||
return MDBX_EBADSIGN;
|
||||
|
||||
int rc = mdbx_fseek(fd, 0);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
const int dest_is_pipe = mdbx_is_pipe(fd);
|
||||
if (MDBX_IS_ERROR(dest_is_pipe))
|
||||
return dest_is_pipe;
|
||||
|
||||
if (!dest_is_pipe) {
|
||||
int rc = mdbx_fseek(fd, 0);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
}
|
||||
|
||||
const size_t buffer_size =
|
||||
pgno2bytes(env, NUM_METAS) +
|
||||
((flags & MDBX_CP_COMPACT) ? MDBX_WBUF * 2 : MDBX_WBUF);
|
||||
|
||||
uint8_t *buffer = NULL;
|
||||
rc = mdbx_memalign_alloc(env->me_os_psize, buffer_size, (void **)&buffer);
|
||||
int rc = mdbx_memalign_alloc(env->me_os_psize, buffer_size, (void **)&buffer);
|
||||
if (unlikely(rc != MDBX_SUCCESS))
|
||||
return rc;
|
||||
|
||||
MDBX_txn *read_txn = NULL;
|
||||
/* Do the lock/unlock of the reader mutex before starting the
|
||||
* write txn. Otherwise other read txns could block writers. */
|
||||
* write txn. Otherwise other read txns could block writers. */
|
||||
rc = mdbx_txn_begin(env, NULL, MDBX_RDONLY, &read_txn);
|
||||
if (unlikely(rc != MDBX_SUCCESS)) {
|
||||
mdbx_memalign_free(buffer);
|
||||
return rc;
|
||||
}
|
||||
|
||||
/* Firstly write a stub to meta-pages.
|
||||
* Now we sure to incomplete copy will not be used. */
|
||||
memset(buffer, -1, pgno2bytes(env, NUM_METAS));
|
||||
rc = mdbx_pwrite(fd, buffer, pgno2bytes(env, NUM_METAS), 0);
|
||||
if (!dest_is_pipe) {
|
||||
/* Firstly write a stub to meta-pages.
|
||||
* Now we sure to incomplete copy will not be used. */
|
||||
memset(buffer, -1, pgno2bytes(env, NUM_METAS));
|
||||
rc = mdbx_write(fd, buffer, pgno2bytes(env, NUM_METAS));
|
||||
}
|
||||
|
||||
if (likely(rc == MDBX_SUCCESS)) {
|
||||
memset(buffer, 0, pgno2bytes(env, NUM_METAS));
|
||||
rc = (flags & MDBX_CP_COMPACT)
|
||||
? mdbx_env_compact(env, read_txn, fd, buffer)
|
||||
: mdbx_env_copy_asis(env, read_txn, fd, buffer);
|
||||
? mdbx_env_compact(env, read_txn, fd, buffer, dest_is_pipe)
|
||||
: mdbx_env_copy_asis(env, read_txn, fd, buffer, dest_is_pipe);
|
||||
}
|
||||
mdbx_txn_abort(read_txn);
|
||||
|
||||
if (likely(rc == MDBX_SUCCESS))
|
||||
rc = mdbx_filesync(fd, MDBX_SYNC_DATA | MDBX_SYNC_SIZE);
|
||||
if (!dest_is_pipe) {
|
||||
if (likely(rc == MDBX_SUCCESS))
|
||||
rc = mdbx_filesync(fd, MDBX_SYNC_DATA | MDBX_SYNC_SIZE | MDBX_SYNC_IODQ);
|
||||
|
||||
/* Write actual meta */
|
||||
if (likely(rc == MDBX_SUCCESS))
|
||||
rc = mdbx_pwrite(fd, buffer, pgno2bytes(env, NUM_METAS), 0);
|
||||
/* Write actual meta */
|
||||
if (likely(rc == MDBX_SUCCESS))
|
||||
rc = mdbx_pwrite(fd, buffer, pgno2bytes(env, NUM_METAS), 0);
|
||||
|
||||
if (likely(rc == MDBX_SUCCESS))
|
||||
rc = mdbx_filesync(fd, MDBX_SYNC_DATA | MDBX_SYNC_IODQ);
|
||||
if (likely(rc == MDBX_SUCCESS))
|
||||
rc = mdbx_filesync(fd, MDBX_SYNC_DATA | MDBX_SYNC_IODQ);
|
||||
}
|
||||
|
||||
mdbx_memalign_free(buffer);
|
||||
return rc;
|
||||
@ -12277,6 +12363,8 @@ int __cold mdbx_env_copy(MDBX_env *env, const char *dest_path, unsigned flags) {
|
||||
return rc;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
|
||||
int __cold mdbx_env_set_flags(MDBX_env *env, unsigned flags, int onoff) {
|
||||
if (unlikely(!env))
|
||||
return MDBX_EINVAL;
|
||||
|
@ -636,9 +636,9 @@ MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
|
||||
ov.OffsetHigh = HIGH_DWORD(offset);
|
||||
|
||||
DWORD written;
|
||||
if (unlikely(!WriteFile(fd, buf,
|
||||
(bytes <= MAX_WRITE) ? (DWORD)bytes : MAX_WRITE,
|
||||
&written, &ov)))
|
||||
if (unlikely(!WriteFile(
|
||||
fd, buf, likely(bytes <= MAX_WRITE) ? (DWORD)bytes : MAX_WRITE,
|
||||
&written, &ov)))
|
||||
return GetLastError();
|
||||
if (likely(bytes == written))
|
||||
return MDBX_SUCCESS;
|
||||
@ -646,7 +646,7 @@ MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
|
||||
STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
|
||||
"libmdbx requires 64-bit file I/O on 64-bit systems");
|
||||
const intptr_t written =
|
||||
pwrite(fd, buf, (bytes <= MAX_WRITE) ? bytes : MAX_WRITE, offset);
|
||||
pwrite(fd, buf, likely(bytes <= MAX_WRITE) ? bytes : MAX_WRITE, offset);
|
||||
if (likely(bytes == (size_t)written))
|
||||
return MDBX_SUCCESS;
|
||||
if (written < 0) {
|
||||
@ -662,6 +662,36 @@ MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
|
||||
}
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
|
||||
size_t bytes) {
|
||||
while (true) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
DWORD written;
|
||||
if (unlikely(!WriteFile(
|
||||
fd, buf, likely(bytes <= MAX_WRITE) ? (DWORD)bytes : MAX_WRITE,
|
||||
&written, nullptr)))
|
||||
return GetLastError();
|
||||
if (likely(bytes == written))
|
||||
return MDBX_SUCCESS;
|
||||
#else
|
||||
STATIC_ASSERT_MSG(sizeof(off_t) >= sizeof(size_t),
|
||||
"libmdbx requires 64-bit file I/O on 64-bit systems");
|
||||
const intptr_t written =
|
||||
write(fd, buf, likely(bytes <= MAX_WRITE) ? bytes : MAX_WRITE);
|
||||
if (likely(bytes == (size_t)written))
|
||||
return MDBX_SUCCESS;
|
||||
if (written < 0) {
|
||||
const int rc = errno;
|
||||
if (rc != EINTR)
|
||||
return rc;
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
bytes -= written;
|
||||
buf = (char *)buf + written;
|
||||
}
|
||||
}
|
||||
|
||||
int mdbx_pwritev(mdbx_filehandle_t fd, struct iovec *iov, int iovcnt,
|
||||
uint64_t offset, size_t expected_written) {
|
||||
#if defined(_WIN32) || defined(_WIN64) || defined(__APPLE__)
|
||||
@ -750,6 +780,37 @@ int mdbx_filesize(mdbx_filehandle_t fd, uint64_t *length) {
|
||||
return MDBX_SUCCESS;
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
switch (GetFileType(fd)) {
|
||||
case FILE_TYPE_DISK:
|
||||
return MDBX_RESULT_FALSE;
|
||||
case FILE_TYPE_CHAR:
|
||||
case FILE_TYPE_PIPE:
|
||||
return MDBX_RESULT_TRUE;
|
||||
default:
|
||||
return GetLastError();
|
||||
}
|
||||
#else
|
||||
struct stat info;
|
||||
if (fstat(fd, &info))
|
||||
return errno;
|
||||
switch (info.st_mode & S_IFMT) {
|
||||
case S_IFBLK:
|
||||
case S_IFREG:
|
||||
return MDBX_RESULT_FALSE;
|
||||
case S_IFCHR:
|
||||
case S_IFIFO:
|
||||
case S_IFSOCK:
|
||||
return MDBX_RESULT_TRUE;
|
||||
case S_IFDIR:
|
||||
case S_IFLNK:
|
||||
default:
|
||||
return MDBX_INCOMPATIBLE;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
MDBX_INTERNAL_FUNC int mdbx_ftruncate(mdbx_filehandle_t fd, uint64_t length) {
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
if (mdbx_SetFileInformationByHandle) {
|
||||
|
@ -85,6 +85,10 @@
|
||||
#endif
|
||||
#endif /* !xBSD */
|
||||
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
#include <sys/sendfile.h>
|
||||
#endif /* Linux */
|
||||
|
||||
#ifndef _XOPEN_SOURCE
|
||||
#define _XOPEN_SOURCE 0
|
||||
#endif
|
||||
@ -494,7 +498,11 @@ MDBX_INTERNAL_FUNC int mdbx_vasprintf(char **strp, const char *fmt, va_list ap);
|
||||
/* OS abstraction layer stuff */
|
||||
|
||||
/* max bytes to write in one call */
|
||||
#if defined(_WIN32) || defined(_WIN64)
|
||||
#define MAX_WRITE UINT32_C(0x01000000)
|
||||
#else
|
||||
#define MAX_WRITE UINT32_C(0x3fff0000)
|
||||
#endif
|
||||
|
||||
#if defined(__linux__) || defined(__gnu_linux__)
|
||||
MDBX_INTERNAL_VAR uint32_t mdbx_linux_kernel_version;
|
||||
@ -553,6 +561,8 @@ MDBX_INTERNAL_FUNC int mdbx_pread(mdbx_filehandle_t fd, void *buf, size_t count,
|
||||
uint64_t offset);
|
||||
MDBX_INTERNAL_FUNC int mdbx_pwrite(mdbx_filehandle_t fd, const void *buf,
|
||||
size_t count, uint64_t offset);
|
||||
MDBX_INTERNAL_FUNC int mdbx_write(mdbx_filehandle_t fd, const void *buf,
|
||||
size_t count);
|
||||
|
||||
MDBX_INTERNAL_FUNC int
|
||||
mdbx_thread_create(mdbx_thread_t *thread,
|
||||
@ -576,6 +586,7 @@ MDBX_INTERNAL_FUNC int mdbx_openfile(const char *pathname, int flags,
|
||||
bool exclusive);
|
||||
MDBX_INTERNAL_FUNC int mdbx_closefile(mdbx_filehandle_t fd);
|
||||
MDBX_INTERNAL_FUNC int mdbx_removefile(const char *pathname);
|
||||
MDBX_INTERNAL_FUNC int mdbx_is_pipe(mdbx_filehandle_t fd);
|
||||
|
||||
typedef struct mdbx_mmap_param {
|
||||
union {
|
||||
|
@ -49,12 +49,15 @@ int main(int argc, char *argv[]) {
|
||||
const char *progname = argv[0], *act;
|
||||
unsigned flags = MDBX_RDONLY;
|
||||
unsigned cpflags = 0;
|
||||
bool quiet = false;
|
||||
|
||||
for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
|
||||
if (argv[1][1] == 'n' && argv[1][2] == '\0')
|
||||
flags |= MDBX_NOSUBDIR;
|
||||
else if (argv[1][1] == 'c' && argv[1][2] == '\0')
|
||||
cpflags |= MDBX_CP_COMPACT;
|
||||
else if (argv[1][1] == 'q' && argv[1][2] == '\0')
|
||||
quiet = true;
|
||||
else if (argv[1][1] == 'V' && argv[1][2] == '\0') {
|
||||
printf("mdbx_copy version %d.%d.%d.%d\n"
|
||||
" - source: %s %s, commit %s, tree %s\n"
|
||||
@ -74,7 +77,8 @@ int main(int argc, char *argv[]) {
|
||||
}
|
||||
|
||||
if (argc < 2 || argc > 3) {
|
||||
fprintf(stderr, "usage: %s [-V] [-c] [-n] srcpath [dstpath]\n", progname);
|
||||
fprintf(stderr, "usage: %s [-V] [-q] [-c] [-n] srcpath [dstpath]\n",
|
||||
progname);
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
@ -91,10 +95,13 @@ int main(int argc, char *argv[]) {
|
||||
signal(SIGTERM, signal_handler);
|
||||
#endif /* !WINDOWS */
|
||||
|
||||
printf("mdbx_copy %s (%s, T-%s)\nRunning for copy %s to %s...\n",
|
||||
mdbx_version.git.describe, mdbx_version.git.datetime,
|
||||
mdbx_version.git.tree, argv[1], (argc == 2) ? "stdout" : argv[2]);
|
||||
fflush(NULL);
|
||||
if (!quiet) {
|
||||
fprintf((argc == 2) ? stderr : stdout,
|
||||
"mdbx_copy %s (%s, T-%s)\nRunning for copy %s to %s...\n",
|
||||
mdbx_version.git.describe, mdbx_version.git.datetime,
|
||||
mdbx_version.git.tree, argv[1], (argc == 2) ? "stdout" : argv[2]);
|
||||
fflush(NULL);
|
||||
}
|
||||
|
||||
act = "opening environment";
|
||||
rc = mdbx_env_create(&env);
|
||||
|
Loading…
Reference in New Issue
Block a user