Skip to content

Adopted LRU from https://github.com/cluck, tested, fixed some issues (fix of issue#20) #22

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open
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
72 changes: 52 additions & 20 deletions sparsebundlefs.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,13 @@
#include <iostream>
#include <limits>
#include <map>
#include <list>
#include <sstream>
#include <streambuf>
#include <string>
#include <vector>
#include <pthread.h>


#include <fuse.h>

Expand All @@ -51,6 +54,8 @@
using namespace std;

static const char image_path[] = "/sparsebundle.dmg";
unsigned int max_open_files = 128;


struct sparsebundle_t {
char *path;
Expand All @@ -60,6 +65,7 @@ struct sparsebundle_t {
off_t times_opened;
#if FUSE_SUPPORTS_ZERO_COPY
map<string, int> open_files;
list<string> lru_files;
#endif
};

Expand Down Expand Up @@ -245,23 +251,53 @@ static int sparsebundle_read(const char *path, char *buffer, size_t length, off_
}

#if FUSE_SUPPORTS_ZERO_COPY
static void sparsebundle_cleanup_open_files()
{
sparsebundle_t *sparsebundle = sparsebundle_current();

syslog(LOG_DEBUG, "lru size: %zu", sparsebundle->lru_files.size());


if (sparsebundle->lru_files.size() >= max_open_files) {
syslog(LOG_DEBUG, "too many open files, closing least recently opened bands");
while (sparsebundle->lru_files.size() * 2 >= max_open_files) {
const char* lru_path = sparsebundle->lru_files.back().c_str();
int c = close(sparsebundle->open_files[lru_path]);
syslog(LOG_DEBUG, "closing %s, result %i", lru_path, c);
sparsebundle->open_files.erase(lru_path);
sparsebundle->lru_files.pop_back(); // be sure to have this as a last line, otherwise it screws lru_path string
}
}
}

pthread_mutex_t lru_lock;

static int sparsebundle_read_buf_prepare_file(const char *path)
{
sparsebundle_t *sparsebundle = sparsebundle_current();

int fd = -1;
//critical section
pthread_mutex_lock(&lru_lock);
syslog(LOG_DEBUG, "thread %zu entered critical section", (unsigned int)pthread_self());
map<string, int>::const_iterator iter = sparsebundle->open_files.find(path);
if (iter != sparsebundle->open_files.end()) {
fd = iter->second;
sparsebundle->lru_files.remove(path); //remove path from LRU - we will store it on top in the end
} else {
syslog(LOG_DEBUG, "file %s not opened yet, opening", path);
sparsebundle_cleanup_open_files();
fd = open(path, O_RDONLY);
sparsebundle->open_files[path] = fd;
}
sparsebundle->lru_files.push_front(path); // store the path on the top of LRU
syslog(LOG_DEBUG, "thread %zu leaving critical section", (unsigned int)pthread_self());
pthread_mutex_unlock(&lru_lock);
//end of critical section

return fd;
}

static int sparsebundle_read_buf_process_band(const char *band_path, size_t length, off_t offset, void *read_data)
{
ssize_t read = 0;
Expand Down Expand Up @@ -305,15 +341,22 @@ static void sparsebundle_read_buf_close_files()
{
sparsebundle_t *sparsebundle = sparsebundle_current();

syslog(LOG_DEBUG, "closing %u open file descriptor(s)", sparsebundle->open_files.size());
syslog(LOG_DEBUG, "closing %zu open file(s)", sparsebundle->lru_files.size());

//critical section
pthread_mutex_lock(&lru_lock);
syslog(LOG_DEBUG, "thread %zu entered critical section", (unsigned int)pthread_self());

map<string, int>::iterator iter;
for(iter = sparsebundle->open_files.begin(); iter != sparsebundle->open_files.end(); ++iter) {
close(iter->second);
syslog(LOG_DEBUG, "closed %s", iter->first.c_str());
while (sparsebundle->lru_files.size() > 0) {
const char* path = sparsebundle->lru_files.back().c_str();
close(sparsebundle->open_files[path]);
sparsebundle->open_files.erase(path);
sparsebundle->lru_files.pop_back();
}

sparsebundle->open_files.clear();
syslog(LOG_DEBUG, "thread %zu leaving critical section", (unsigned int)pthread_self());
pthread_mutex_unlock(&lru_lock);
//end of critical section
}

static int sparsebundle_read_buf(const char *path, struct fuse_bufvec **bufp,
Expand All @@ -332,18 +375,6 @@ static int sparsebundle_read_buf(const char *path, struct fuse_bufvec **bufp,
syslog(LOG_DEBUG, "asked to read %zu bytes at offset %ju using zero-copy read",
length, uintmax_t(offset));

static struct rlimit fd_limit;
static bool fd_limit_computed = false;
if (!fd_limit_computed) {
getrlimit(RLIMIT_NOFILE, &fd_limit);
fd_limit_computed = true;
}

sparsebundle_t *sparsebundle = sparsebundle_current();
if (sparsebundle->open_files.size() + 1 >= fd_limit.rlim_cur) {
syslog(LOG_DEBUG, "hit max number of file descriptors");
sparsebundle_read_buf_close_files();
}

ret = sparsebundle_iterate_bands(path, length, offset, &read_ops);
if (ret < 0)
Expand Down Expand Up @@ -452,7 +483,7 @@ static off_t read_size(const string &str)

int main(int argc, char **argv)
{
openlog("sparsebundlefs", LOG_CONS | LOG_PERROR, LOG_USER);
openlog("sparsebundlefs", LOG_CONS | LOG_PERROR | LOG_PID, LOG_USER);
setlogmask(~(LOG_MASK(LOG_DEBUG)));

struct sparsebundle_t sparsebundle = {};
Expand Down Expand Up @@ -516,3 +547,4 @@ int main(int argc, char **argv)

return fuse_main(args.argc, args.argv, &sparsebundle_filesystem_operations, &sparsebundle);
}