Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions include/relpath_parse.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,25 @@ inline bool parseRelnodePath(const std::string &fileName, uint32_t *dbOidOut,
}
if (dbOid == 0) {
while (it < len && isdigit((unsigned char)fileName[it])) {
if (dbOid > UINT32_MAX / 10) {
return false;
}
dbOid *= 10;
dbOid += fileName[it++] - '0';
}
} else if (relfilenodeOid == 0) {
while (it < len && isdigit((unsigned char)fileName[it])) {
if (relfilenodeOid > UINT32_MAX / 10) {
return false;
}
relfilenodeOid *= 10;
relfilenodeOid += fileName[it++] - '0';
}
} else if (blkno == 0) {
while (it < len && isdigit((unsigned char)fileName[it])) {
if (blkno > INT64_MAX / 10) {
return false;
}
blkno *= 10;
blkno += fileName[it++] - '0';
}
Expand Down
8 changes: 5 additions & 3 deletions include/url.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,12 @@ std::string yezzey_fqrelname_md5(const std::string &nspname,
*
*/
std::string yezzey_block_file_path(const std::string &nspname,
const std::string &relname,
relnodeCoord coords, int32_t segid);
const std::string &relname,
relnodeCoord coords, int32_t segid);

/* yezzey_block_namespace_path is defined inline in yezzey_standalone.h
* (included via util.h) */

std::string yezzey_block_namespace_path(int32_t segid);
std::string yezzey_block_db_file_path(const std::string &nspname,
const std::string &relname,
relnodeCoord coords, int32_t segid);
Expand Down
6 changes: 1 addition & 5 deletions include/util.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,7 @@ int64_t yezzey_calc_virtual_relation_size(std::shared_ptr<IOadv> adv,
ssize_t segindx, ssize_t modcount,
const std::string &storage_path);

std::string storage_url_add_options(const std::string &s3path,
const char *config_path);

std::string make_yezzey_url(const std::string &prefix, int64_t modcounts,
XLogRecPtr current_recptr);
#include "yezzey_standalone.h"

std::vector<int64_t> parseModcounts(const std::string &prefix,
std::string name);
Expand Down
74 changes: 74 additions & 0 deletions include/yezzey_standalone.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
#pragma once

#include <cctype>
#include <cstdint>
#include <string>
#include <vector>

/*
* Header-only pure utility functions, testable without PostgreSQL headers.
* Defined here so they can be unit-tested standalone (cf. relpath_parse.h).
* util.cpp / url.cpp include this header; the symbols are defined inline.
*/

#ifndef InvalidXLogRecPtr
#define InvalidXLogRecPtr ((uint64_t)0)
#endif

extern const char *baseYezzeyPath;

inline std::string storage_url_add_options(const std::string &s3path,
const char *config_path) {
auto ret = s3path;

ret += " config=";
ret += config_path;
ret += " region=us-east-1";

return ret;
}

inline std::vector<int64_t>
parseModcountsInternal(const std::string &prefix, std::string name) {
std::vector<int64_t> res;
auto indx = name.find(prefix);
if (indx == std::string::npos) {
return res;
}
indx += prefix.size();
auto endindx = name.find("_aoseg", indx);

size_t prev = 0;

/* name[endindx] -> not digit */
/* mc1_D_mc2_D_mc3_D_mc4 */
for (size_t it = indx; it <= endindx; ++it) {
if (!isdigit((unsigned char)name[it])) {
if (prev) {
res.push_back(prev);
}
prev = 0;
continue;
}
if (prev > SIZE_MAX / 10) {
break;
}
prev *= 10;
prev += name[it] - '0';
}

return res;
}

inline std::string make_yezzey_url(const std::string &prefix, int64_t modcount,
uint64_t current_recptr) {
std::string rv = prefix + ("_DY_" + std::to_string(modcount));
if (current_recptr != InvalidXLogRecPtr) {
rv += "_xlog_" + std::to_string(current_recptr);
}
return rv;
}

inline std::string yezzey_block_namespace_path(int32_t segid) {
return "/segments_005/seg" + std::to_string(segid) + baseYezzeyPath;
}
5 changes: 5 additions & 0 deletions src/storage.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -562,6 +562,11 @@ int statRelationChunksSpaceUsage(Relation aorel, size_t *local_bytes,
Assert((*cnt_chunks) >= 0);

// do copy;
if (*cnt_chunks > 0 &&
*cnt_chunks > SIZE_MAX / sizeof(struct yezzeyChunkMeta)) {
elog(ERROR, "yezzey: chunk count overflow in list_relation_chunks");
}

*list = (struct yezzeyChunkMeta *)palloc(sizeof(struct yezzeyChunkMeta) *
(*cnt_chunks));

Expand Down
6 changes: 2 additions & 4 deletions src/url.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,10 +32,8 @@ std::string yezzey_fqrelname_md5(const std::string &nspname,
return std::string(md);
}

/* creates yezzey xternal storage namespace prefix path */
std::string yezzey_block_namespace_path(int32_t segid) {
return "/segments_005/seg" + std::to_string(segid) + baseYezzeyPath;
}
/* yezzey_block_namespace_path is defined inline in yezzey_standalone.h */

/* creates yezzey xternal storage prefix path */
std::string yezzey_block_db_file_path(const std::string &nspname,
const std::string &relname,
Expand Down
30 changes: 5 additions & 25 deletions src/util.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,22 +18,12 @@
#include "url.h"

#include "relpath_parse.h"
#include "yezzey_standalone.h"

#define DEFAULTTABLESPACE_OID 1663 /* FIXME */

const char *baseYezzeyPath = "/basebackups_005/yezzey/";

std::string storage_url_add_options(const std::string &s3path,
const char *config_path) {
auto ret = s3path;

ret += " config=";
ret += config_path;
ret += " region=us-east-1";

return ret;
}

relnodeCoord getRelnodeCoordinate(Oid spcNode, const std::string &fileName) {
uint32_t dbOid = 0;
uint32_t relfilenodeOid = 0;
Expand Down Expand Up @@ -62,10 +52,6 @@ void getYezzeyExternalStoragePathByCoords(const char *nspname,
return;
}

/*
* fileName is in form 'base=DEFAULTTABLESPACE_OID/<dboid>/<tableoid>.<seg>'
*/

std::vector<int64_t> parseModcounts(const std::string &prefix,
std::string name) {
std::vector<int64_t> res;
Expand All @@ -81,29 +67,23 @@ std::vector<int64_t> parseModcounts(const std::string &prefix,
/* name[endindx] -> not digit */
/* mc1_D_mc2_D_mc3_D_mc4 */
for (size_t it = indx; it <= endindx; ++it) {
if (!isdigit(name[it])) {
if (!isdigit((unsigned char)name[it])) {
if (prev) {
res.push_back(prev);
}
prev = 0;
continue;
}
if (prev > SIZE_MAX / 10) {
elog(ERROR, "yezzey: modcount overflow in path %s", name.c_str());
}
prev *= 10;
prev += name[it] - '0';
}

return res;
}

std::string make_yezzey_url(const std::string &prefix, int64_t modcount,
XLogRecPtr current_recptr) {
std::string rv = prefix + ("_DY_" + std::to_string(modcount));
if (current_recptr != InvalidXLogRecPtr) {
rv += "_xlog_" + std::to_string(current_recptr);
}
return rv;
}

/* calc size of external files */
int64_t yezzey_virtual_relation_size(std::shared_ptr<IOadv> adv,
int32_t segid) {
Expand Down
2 changes: 1 addition & 1 deletion test/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ TEST_OBJS = $(patsubst %.o,%_test.o,$(COMMON_OBJS))

# Standalone tests that only exercise header-only, PG-independent helpers and
# therefore need no matching src/ object file.
STANDALONE_TEST_OBJS = relpath_parse_test.o
STANDALONE_TEST_OBJS = relpath_parse_test.o scope_guard_test.o meta_test.o util_test.o url_test.o
TEST_OBJS += $(STANDALONE_TEST_OBJS)

# Options
Expand Down
39 changes: 39 additions & 0 deletions test/meta_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
#include "gtest/gtest.h"

#include "meta.h"

#include <memory>
#include <string>

TEST(MakeUnique, CreatesPrimitive) {
auto p = make_unique<int>(42);
ASSERT_NE(p, nullptr);
EXPECT_EQ(*p, 42);
}

TEST(MakeUnique, CreatesString) {
auto p = make_unique<std::string>("hello");
ASSERT_NE(p, nullptr);
EXPECT_EQ(*p, "hello");
EXPECT_EQ(p->size(), 5u);
}

TEST(MakeUnique, CreatesWithMultipleArgs) {
struct Pair {
int a;
int b;
Pair(int a, int b) : a(a), b(b) {}
};
auto p = make_unique<Pair>(1, 2);
ASSERT_NE(p, nullptr);
EXPECT_EQ(p->a, 1);
EXPECT_EQ(p->b, 2);
}

TEST(MakeUnique, ManagesOwnership) {
auto p = make_unique<int>(7);
auto raw = p.get();
p.reset();
EXPECT_EQ(p.get(), nullptr);
(void)raw;
}
40 changes: 40 additions & 0 deletions test/scope_guard_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
#include "gtest/gtest.h"

#include "scope_guard.h"

#include <memory>

TEST(ScopeGuard, RunsOnScopeExit) {
bool fired = false;
{
auto guard = makeScopeGuard([&] { fired = true; });
}
EXPECT_TRUE(fired);
}

TEST(ScopeGuard, DismissPreventsCall) {
bool fired = false;
{
auto guard = makeScopeGuard([&] { fired = true; });
guard.dismiss();
}
EXPECT_FALSE(fired);
}

TEST(ScopeGuard, MoveTransfersOwnership) {
bool fired = false;
{
auto guard1 = makeScopeGuard([&] { fired = true; });
ScopeGuard<decltype(guard1)> guard2(std::move(guard1));
}
EXPECT_TRUE(fired);
}

TEST(ScopeGuard, MovedFromDoesNotFire) {
int count = 0;
{
auto guard1 = makeScopeGuard([&] { count++; });
auto guard2 = std::move(guard1);
}
EXPECT_EQ(count, 1);
}
25 changes: 25 additions & 0 deletions test/url_test.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#include "gtest/gtest.h"

#include "yezzey_standalone.h"

const char *baseYezzeyPath = "/basebackups_005/yezzey/";

TEST(YezzeyBlockNamespacePath, SegZero) {
auto result = yezzey_block_namespace_path(0);
EXPECT_EQ(result, "/segments_005/seg0/basebackups_005/yezzey/");
}

TEST(YezzeyBlockNamespacePath, SegOne) {
auto result = yezzey_block_namespace_path(1);
EXPECT_EQ(result, "/segments_005/seg1/basebackups_005/yezzey/");
}

TEST(YezzeyBlockNamespacePath, LargeSegId) {
auto result = yezzey_block_namespace_path(999);
EXPECT_EQ(result, "/segments_005/seg999/basebackups_005/yezzey/");
}

TEST(YezzeyBlockNamespacePath, NegativeSegId) {
auto result = yezzey_block_namespace_path(-1);
EXPECT_EQ(result, "/segments_005/seg-1/basebackups_005/yezzey/");
}
Loading
Loading