Skip to content
Merged
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
10 changes: 9 additions & 1 deletion src/image_file.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,10 +41,15 @@ static std::string SEALED_FILE_NAME = "overlaybd.sealed";

class ImageFile : public photon::fs::ForwardFile {
public:
ImageFile(ImageConfigNS::ImageConfig &_conf, ImageService &is)
ImageFile(ImageConfigNS::ImageConfig &_conf, ImageService &is, const std::string &dev_id)
: ForwardFile(nullptr), image_service(is), m_lower_file(nullptr) {
conf.CopyFrom(_conf, conf.GetAllocator());
m_exception = "";
if(image_service.register_image_file(dev_id, this) != 0) { // register itself
set_failed("duplicated dev id: " + dev_id);
return;
}
m_dev_id = dev_id;
m_status = init_image_file();
if (m_status == 1) {
struct stat st;
Expand All @@ -55,6 +60,7 @@ class ImageFile : public photon::fs::ForwardFile {

~ImageFile() {
m_status = -1;
image_service.unregister_image_file(m_dev_id); // unregister itself
if (dl_thread_jh != nullptr)
photon::thread_join(dl_thread_jh);
delete m_prefetcher;
Expand Down Expand Up @@ -117,6 +123,7 @@ class ImageFile : public photon::fs::ForwardFile {
// load new config file to get the snapshot layer path
// open new upper layer
// restack() current RW layer as snapshot layer
return 0;
}

private:
Expand All @@ -127,6 +134,7 @@ class ImageFile : public photon::fs::ForwardFile {
ImageService &image_service;
photon::fs::IFile *m_lower_file = nullptr;
photon::fs::IFile *m_upper_file = nullptr;
std::string m_dev_id = "";

int init_image_file();
template<typename...Ts> void set_failed(const Ts&...xs);
Expand Down
27 changes: 25 additions & 2 deletions src/image_service.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -470,7 +470,7 @@ bool ImageService::enable_acceleration() {
}
}

ImageFile *ImageService::create_image_file(const char *config_path) {
ImageFile *ImageService::create_image_file(const char *config_path, const std::string &dev_id) {
ImageConfigNS::GlobalConfig defaultDlCfg;
if (!defaultDlCfg.ParseJSON(m_config_path)) {
LOG_WARN("default download config parse failed, ignore");
Expand All @@ -493,7 +493,7 @@ ImageFile *ImageService::create_image_file(const char *config_path) {
}

auto resFile = cfg.resultFile();
ImageFile *ret = new ImageFile(cfg, *this);
ImageFile *ret = new ImageFile(cfg, *this, dev_id);
if (ret->m_status <= 0) {
std::string data = "failed:" + ret->m_exception;
set_result_file(resFile, data);
Expand All @@ -505,6 +505,29 @@ ImageFile *ImageService::create_image_file(const char *config_path) {
return ret;
}

int ImageService::register_image_file(const std::string& dev_id, ImageFile* file) {
if (dev_id.empty())
return 0;
if(find_image_file(dev_id) != nullptr)
LOG_ERROR_RETURN(0, -1, "dev id exists: `", dev_id);
m_image_files[dev_id] = file;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is no need to set a scoped_lock here.
It's thread safe.

LOG_INFO("Registered image file for dev_id: `", dev_id);
return 0;
}

int ImageService::unregister_image_file(const std::string& dev_id) {
if (dev_id.empty())
return 0;
m_image_files.erase(dev_id);
LOG_INFO("Unregistered image file for dev_id: `", dev_id);
return 0;
}

ImageFile* ImageService::find_image_file(const std::string& dev_id) {
auto it = m_image_files.find(dev_id);
return (it != m_image_files.end()) ? it->second : nullptr;
}

ImageService::ImageService(const char *config_path) {
m_config_path = config_path ? config_path : DEFAULT_CONFIG_PATH;
}
Expand Down
7 changes: 6 additions & 1 deletion src/image_service.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
#include "overlaybd/cache/gzip_cache/cached_fs.h"
#include <photon/fs/filesystem.h>
#include <photon/common/io-alloc.h>
#include <unordered_map>

using namespace photon::fs;

Expand Down Expand Up @@ -54,9 +55,12 @@ class ImageService {
ImageService(const char *config_path = nullptr);
~ImageService();
int init();
ImageFile *create_image_file(const char *image_config_path);
ImageFile *create_image_file(const char *image_config_path, const std::string &dev_id);
// bool enable_acceleration(GlobalFs *global_fs, ImageConfigNS::P2PConfig conf);
bool enable_acceleration();
int register_image_file(const std::string& dev_id, ImageFile* file);
int unregister_image_file(const std::string& dev_id);
ImageFile* find_image_file(const std::string& dev_id);


ImageConfigNS::GlobalConfig global_conf;
Expand All @@ -69,6 +73,7 @@ class ImageService {
std::pair<std::string, std::string> reload_auth(const char *remote_path);
void set_result_file(std::string &filename, std::string &data);
std::string m_config_path;
std::unordered_map<std::string, ImageFile*> m_image_files; // dev_id -> ImageFile*
};

ImageService *create_image_service(const char *config_path = nullptr);
Expand Down
14 changes: 10 additions & 4 deletions src/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "version.h"
#include "image_file.h"
#include "image_service.h"
#include "tools/comm_func.h"
#include <photon/common/alog.h>
#include <photon/common/event-loop.h>
#include <photon/fs/filesystem.h>
Expand All @@ -34,6 +35,7 @@
#include <scsi/scsi.h>
#include <sys/resource.h>
#include <sys/prctl.h>
#include <string>

class TCMUDevLoop;

Expand All @@ -46,6 +48,7 @@ struct obd_dev {
uint32_t inflight;
std::thread *work;
photon::semaphore start, end;
std::string dev_id;
};

struct handle_args {
Expand Down Expand Up @@ -303,7 +306,7 @@ class TCMUDevLoop {
};

static char *tcmu_get_path(struct tcmu_device *dev) {
char *config = strchr(tcmu_dev_get_cfgstring(dev), '/');
char *config = strchr(tcmu_dev_get_cfgstring(dev), '/'); // dev_config=overlaybd/<config_path>[;<dev_id>]
if (!config) {
LOG_ERROR("no configuration found in cfgstring");
return NULL;
Expand All @@ -314,16 +317,18 @@ static char *tcmu_get_path(struct tcmu_device *dev) {
}

static int dev_open(struct tcmu_device *dev) {
char *config = tcmu_get_path(dev);
char *config = tcmu_get_path(dev); // <config_path>[;<dev_id>]
LOG_INFO("dev open `", config);
if (!config) {
LOG_ERROR_RETURN(0, -EPERM, "get image config path failed");
}
std::string config_path, dev_id;
parse_config_and_dev_id(config, config_path, dev_id);

struct timeval start;
gettimeofday(&start, NULL);

ImageFile *file = imgservice->create_image_file(config);
ImageFile *file = imgservice->create_image_file(config_path.c_str(), dev_id);
if (file == nullptr) {
LOG_ERROR_RETURN(0, -EPERM, "create image file failed");
}
Expand All @@ -332,6 +337,7 @@ static int dev_open(struct tcmu_device *dev) {
odev->aio_pending_wakeups = 0;
odev->inflight = 0;
odev->file = file;
odev->dev_id = dev_id;

tcmu_dev_set_private(dev, odev);
tcmu_dev_set_block_size(dev, file->block_size);
Expand Down Expand Up @@ -366,7 +372,7 @@ static int dev_open(struct tcmu_device *dev) {
gettimeofday(&end, NULL);

uint64_t elapsed = 1000000UL * (end.tv_sec - start.tv_sec) + end.tv_usec - start.tv_usec;
LOG_INFO("dev opened `, time cost ` ms", config, elapsed / 1000);
LOG_INFO("dev opened `, time cost ` ms", config_path.c_str(), elapsed / 1000);
return 0;
}

Expand Down
6 changes: 3 additions & 3 deletions src/overlaybd/lsmt/file.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -948,7 +948,7 @@ class LSMTFile : public LSMTReadOnlyFile {
}
auto p = new LSMTReadOnlyFile;
p->m_index = new_index;
p->m_files = {nullptr, m_files.back()};
p->m_files = {m_files.back()};//p->m_files = {nullptr, m_files.back()};
p->m_vsize = m_vsize;
p->m_file_ownership = m_file_ownership;
m_file_ownership = false;
Expand Down Expand Up @@ -1025,8 +1025,8 @@ class LSMTFile : public LSMTReadOnlyFile {
auto u = top_layer;

LOG_INFO("m_files.insert new layer: file ptr: 0x`", u->m_files[0]);
// m_files[m_rw_tag] = ((LSMTReadOnlyFile*)gc_layer)->m_files[1];
m_files.insert(m_files.begin(), ((LSMTReadOnlyFile*)gc_layer)->m_files[1]);
// m_files[m_rw_tag] = ((LSMTReadOnlyFile*)gc_layer)->m_files[0];
m_files.insert(m_files.begin(), ((LSMTReadOnlyFile*)gc_layer)->m_files[0]);
m_rw_tag++;
m_files[m_rw_tag] = u->m_files[0]; // fnew_layer;
if (m_file_ownership){
Expand Down
97 changes: 96 additions & 1 deletion src/test/image_service_test.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,15 @@
#include "photon/net/curl.h"
#include "../version.h"
#include <photon/net/http/client.h>
#include <photon/fs/localfs.h>


#include <unistd.h>
#include <fcntl.h>

#include "../image_service.cpp"
#include "../image_service.h"
#include "../image_file.h"
#include "../tools/comm_func.h"

char *test_ua = nullptr;

Expand Down Expand Up @@ -160,7 +164,98 @@ TEST(http_client, user_agent) {
EXPECT_EQ(true, buf == "success");
}

class DevIDTest : public ::testing::Test {
public:
ImageService *imgservice;
const std::string test_dir = "/tmp/overlaybd";
const std::string global_config_path = test_dir + "/global_config.json";
const std::string image_config_path = test_dir + "/image_config.json";
const std::string global_config_content = R"delimiter({
"enableAudit": false,
"logPath": "",
"p2pConfig": {
"enable": false,
"address": "localhost:64210"
}
})delimiter";
const std::string image_config_content = R"delimiter({
"lowers" : [
{
"file" : "/opt/overlaybd/baselayers/ext4_64"
}
]
})delimiter";

virtual void SetUp() override {
// set_log_output_level(0);
system(("mkdir -p " + test_dir).c_str());

system(("echo \'" + global_config_content + "\' > " + global_config_path).c_str());
LOG_INFO("Global config file: ");
system(("cat " + global_config_path).c_str());

system(("echo \'" + image_config_content + "\' > " + image_config_path).c_str());
LOG_INFO("Image config file: ");
system(("cat " + image_config_path).c_str());

imgservice = create_image_service(global_config_path.c_str());
if(imgservice == nullptr) {
LOG_ERROR("failed to create image service");
exit(-1);
}
}
virtual void TearDown() override {
delete imgservice;
system(("rm -rf " + test_dir).c_str());
}
};

TEST_F(DevIDTest, parse_config_with_dev_id) {
std::string config_path, dev_id;
parse_config_and_dev_id("path/to/config.v1.json;123", config_path, dev_id);
EXPECT_EQ(config_path, "path/to/config.v1.json");
EXPECT_EQ(dev_id, "123");
}

TEST_F(DevIDTest, parse_config_without_dev_id) {
std::string config_path, dev_id;
parse_config_and_dev_id("path/to/config.v1.json", config_path, dev_id);
EXPECT_EQ(config_path, "path/to/config.v1.json");
EXPECT_EQ(dev_id, "");
}

TEST_F(DevIDTest, registers) {
ImageFile* imagefile0 = imgservice->create_image_file(image_config_path.c_str(), "");
ImageFile* imagefile1 = imgservice->create_image_file(image_config_path.c_str(), "111");
ImageFile* imagefile2 = imgservice->create_image_file(image_config_path.c_str(), "222");
ImageFile* imagefile3 = imgservice->create_image_file(image_config_path.c_str(), "333");

EXPECT_NE(imagefile0, nullptr);
EXPECT_NE(imagefile1, nullptr);
EXPECT_NE(imagefile2, nullptr);
EXPECT_NE(imagefile3, nullptr);

EXPECT_EQ(imgservice->find_image_file(""), nullptr);
EXPECT_EQ(imgservice->find_image_file("111"), imagefile1);
EXPECT_EQ(imgservice->find_image_file("222"), imagefile2);
EXPECT_EQ(imgservice->find_image_file("333"), imagefile3);

delete imagefile2;

EXPECT_EQ(imgservice->find_image_file(""), nullptr);
EXPECT_EQ(imgservice->find_image_file("111"), imagefile1);
EXPECT_EQ(imgservice->find_image_file("222"), nullptr);
EXPECT_EQ(imgservice->find_image_file("333"), imagefile3);

ImageFile* dup = imgservice->create_image_file(image_config_path.c_str(), "111");

EXPECT_EQ(dup, nullptr);
EXPECT_EQ(imgservice->find_image_file("111"), imagefile1);

delete imagefile0;
delete imagefile1;
delete imagefile3;
}

int main(int argc, char** argv) {
photon::init(photon::INIT_EVENT_DEFAULT, photon::INIT_IO_DEFAULT);
Expand Down
16 changes: 15 additions & 1 deletion src/tools/comm_func.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
#include "../image_service.h"
#include "../image_file.h"
#include "../overlaybd/tar/erofs/erofs_fs.h"
#include <string>
#include <cstring>


using namespace std;
Expand Down Expand Up @@ -51,7 +53,7 @@ int create_overlaybd(const std::string &srv_config, const std::string &dev_confi
fprintf(stderr, "failed to create image service\n");
exit(-1);
}
imgfile = imgservice->create_image_file(dev_config.c_str());
imgfile = imgservice->create_image_file(dev_config.c_str(), "");
if (imgfile == nullptr) {
fprintf(stderr, "failed to create image file\n");
exit(-1);
Expand Down Expand Up @@ -112,3 +114,15 @@ IFile *create_uploader(ZFile::CompressArgs *zfile_args, IFile *src,
}
return upload_builder;
}

void parse_config_and_dev_id(const char *raw_config, std::string &config_path, std::string &dev_id) {
const char *semicolon = strchr(raw_config, ';');
if(!semicolon) {
config_path = std::string(raw_config);
dev_id = std::string("");
}
else {
config_path = std::string(raw_config, semicolon - raw_config);
dev_id = std::string(semicolon + 1);
}
}
2 changes: 2 additions & 0 deletions src/tools/comm_func.h
Original file line number Diff line number Diff line change
Expand Up @@ -50,3 +50,5 @@ photon::fs::IFileSystem *create_ext4fs(photon::fs::IFile *imgfile, bool mkfs,

bool is_erofs_fs(const photon::fs::IFile *imgfile);
photon::fs::IFileSystem *create_erofs_fs(photon::fs::IFile *imgfile, uint64_t blksz);

void parse_config_and_dev_id(const char *raw_config, std::string &config_path, std::string &dev_id);