1
0
mirror of https://github.com/mariadb-corporation/mariadb-columnstore-engine.git synced 2025-12-17 01:02:23 +03:00

First cut of IOC::truncate(). Got some of the unit test

written.  Fixed some bugs.  Commented out the old truncate test
for now; depends on IOC::write() to extend a file.
This commit is contained in:
Patrick LeBlanc
2019-04-01 16:23:35 -05:00
parent d0aeffca07
commit b4ebf7c3c0
7 changed files with 232 additions and 51 deletions

View File

@@ -215,7 +215,7 @@ int IOCoordinator::read(const char *filename, uint8_t *data, off_t offset, size_
const auto &jit = journalFDs.find(object.key); const auto &jit = journalFDs.find(object.key);
// if this is the first object, the offset to start reading at is offset - object->offset // if this is the first object, the offset to start reading at is offset - object->offset
off_t thisOffset = (object.offset == 0 ? offset - object.offset : 0); off_t thisOffset = (object.offset <= offset ? offset - object.offset : 0);
// if this is the last object, the length of the read is length - count, // if this is the last object, the length of the read is length - count,
// otherwise it is the length of the object // otherwise it is the length of the object
@@ -345,32 +345,16 @@ int IOCoordinator::append(const char *filename, const uint8_t *data, size_t leng
return count; return count;
} }
// TODO: might need to support more open flags, ex: O_EXCL
int IOCoordinator::open(const char *filename, int openmode, struct stat *out) int IOCoordinator::open(const char *filename, int openmode, struct stat *out)
{ {
ScopedReadLock s(this, filename);
if (openmode & O_CREAT) MetadataFile meta(filename, MetadataFile::no_create_t());
{
MetadataFile meta(filename);
return meta.stat(out);
}
else
{
MetadataFile meta(filename, MetadataFile::no_create_t());
return meta.stat(out);
}
#if 0 if ((openmode & O_CREAT) && !meta.exists())
int fd, err; replicator->updateMetadata(filename, meta); // this will end up creating filename
return meta.stat(out);
/* create all subdirs if necessary. We don't care if directories actually get created. */
if (openmode & O_CREAT) {
bf::path p(filename);
boost::system::error_code ec;
bf::create_directories(p.parent_path(), ec);
}
OPEN(filename, openmode);
return fstat(fd, out);
#endif
} }
int IOCoordinator::listDirectory(const char *filename, vector<string> *listing) int IOCoordinator::listDirectory(const char *filename, vector<string> *listing)
@@ -402,9 +386,83 @@ int IOCoordinator::stat(const char *path, struct stat *out)
return meta.stat(out); return meta.stat(out);
} }
int IOCoordinator::truncate(const char *path, size_t newsize) int IOCoordinator::truncate(const char *path, size_t newSize)
{ {
return ::truncate(path, newsize); /*
grab the write lock.
get the relevant metadata.
truncate the metadata.
tell replicator to write the new metadata
release the lock
tell replicator to delete all of the objects that no longer exist & their journal files
tell cache they were deleted
tell synchronizer they were deleted
*/
synchronizer = Synchronizer::get(); // need to init sync here to break circular dependency...
int err;
ScopedWriteLock lock(this, path);
MetadataFile meta(path, MetadataFile::no_create_t());
if (!meta.exists())
{
errno = ENOENT;
return -1;
}
size_t filesize = meta.getLength();
if (filesize == newSize)
return 0;
// extend the file, going to make IOC::write() do it
if (filesize < newSize)
{
lock.unlock();
uint8_t zero = 0;
err = write(path, &zero, newSize - 1, 1);
if (err < 0)
return -1;
return 0;
}
vector<metadataObject> objects = meta.metadataRead(newSize, filesize);
// truncate the file
if (newSize == objects[0].offset)
meta.removeEntry(objects[0].offset);
else
meta.updateEntryLength(objects[0].offset, newSize - objects[0].offset);
for (uint i = 1; i < objects.size(); i++)
meta.removeEntry(objects[i].offset);
err = replicator->updateMetadata(path, meta);
if (err)
return err;
lock.unlock();
uint i = (newSize == objects[0].offset ? 0 : 1);
vector<string> deletedObjects;
while (i < objects.size())
{
bf::path cached = cachePath / objects[i].key;
bf::path journal = journalPath / (objects[i].key + ".journal");
if (bf::exists(journal))
{
size_t jsize = bf::file_size(journal);
replicator->remove(journal);
cache->deletedJournal(jsize);
}
size_t fsize = bf::file_size(cached);
replicator->remove(cached);
cache->deletedObject(objects[i].key, fsize);
deletedObjects.push_back(objects[i].key);
++i;
}
if (!deletedObjects.empty())
synchronizer->deletedObjects(deletedObjects);
return 0;
} }
/* Might need to rename this one. The corresponding fcn in IDBFileSystem specifies that it /* Might need to rename this one. The corresponding fcn in IDBFileSystem specifies that it

View File

@@ -30,6 +30,7 @@ class IOCoordinator : public boost::noncopyable
virtual ~IOCoordinator(); virtual ~IOCoordinator();
void willRead(const char *filename, off_t offset, size_t length); void willRead(const char *filename, off_t offset, size_t length);
/* TODO: make read, write, append return a ssize_t */
int read(const char *filename, uint8_t *data, off_t offset, size_t length); int read(const char *filename, uint8_t *data, off_t offset, size_t length);
int write(const char *filename, const uint8_t *data, off_t offset, size_t length); int write(const char *filename, const uint8_t *data, off_t offset, size_t length);
int append(const char *filename, const uint8_t *data, size_t length); int append(const char *filename, const uint8_t *data, size_t length);
@@ -74,6 +75,7 @@ class IOCoordinator : public boost::noncopyable
Cache *cache; Cache *cache;
SMLogging *logger; SMLogging *logger;
Replicator *replicator; Replicator *replicator;
Synchronizer *synchronizer;
size_t objectSize; size_t objectSize;
boost::filesystem::path journalPath; boost::filesystem::path journalPath;
boost::filesystem::path cachePath; boost::filesystem::path cachePath;

View File

@@ -157,7 +157,6 @@ MetadataFile::MetadataFile(const char* filename, no_create_t)
MetadataFile::~MetadataFile() MetadataFile::~MetadataFile()
{ {
} }
int MetadataFile::stat(struct stat *out) const int MetadataFile::stat(struct stat *out) const
@@ -166,11 +165,16 @@ int MetadataFile::stat(struct stat *out) const
if (err) if (err)
return err; return err;
out->st_size = getLength();
return 0;
}
size_t MetadataFile::getLength() const
{
size_t totalSize = 0; size_t totalSize = 0;
for (auto &object : mObjects) for (auto &object : mObjects)
totalSize += object.length; totalSize += object.length;
out->st_size = totalSize; return totalSize;
return 0;
} }
bool MetadataFile::exists() const bool MetadataFile::exists() const
@@ -178,7 +182,7 @@ bool MetadataFile::exists() const
return _exists; return _exists;
} }
vector<metadataObject> MetadataFile::metadataRead(off_t offset, size_t length) vector<metadataObject> MetadataFile::metadataRead(off_t offset, size_t length) const
{ {
// this version assumes mObjects is sorted by offset, and there are no gaps between objects // this version assumes mObjects is sorted by offset, and there are no gaps between objects
vector<metadataObject> ret; vector<metadataObject> ret;
@@ -187,8 +191,11 @@ vector<metadataObject> MetadataFile::metadataRead(off_t offset, size_t length)
auto i = mObjects.begin(); auto i = mObjects.begin();
// find the first object in range // find the first object in range
while (i != mObjects.end()) while (i != mObjects.end())
if (offset >= i->offset) {
if (offset <= (i->offset + i->length - 1))
break; break;
++i;
}
// append objects until foundLen >= length or EOF // append objects until foundLen >= length or EOF
while (i != mObjects.end() && foundLen < length) while (i != mObjects.end() && foundLen < length)
@@ -285,6 +292,35 @@ int MetadataFile::writeMetadata(const char *filename)
return error; return error;
} }
/*
void MetadataFile::truncate(size_t newLength)
{
// there's only one object to modify; the objects after it are deleted
auto &it = mObjects.begin();
while (it != mObjects.end())
{
size_t lastOffset = it->offset + it->length - 1;
if (lastOffset > newLength)
{
it->length = newLength - it->offset;
++it;
break;
}
++it;
}
while (it != mObjects.end())
{
auto toDelete = it++;
mObjects.erase(toDelete);
}
}
*/
void MetadataFile::removeEntry(off_t offset)
{
mObjects.erase(offset);
}
string MetadataFile::getNewKeyFromOldKey(const string &key, size_t length) string MetadataFile::getNewKeyFromOldKey(const string &key, size_t length)
{ {
boost::uuids::uuid u = boost::uuids::random_generator()(); boost::uuids::uuid u = boost::uuids::random_generator()();
@@ -352,7 +388,7 @@ void MetadataFile::setLengthInKey(string &key, size_t newLength)
key = oss.str(); key = oss.str();
} }
void MetadataFile::printObjects() void MetadataFile::printObjects() const
{ {
printf("Version: %i Revision: %i\n",mVersion,mRevision); printf("Version: %i Revision: %i\n",mVersion,mRevision);
for (std::set<metadataObject>::const_iterator i = mObjects.begin(); i != mObjects.end(); ++i) for (std::set<metadataObject>::const_iterator i = mObjects.begin(); i != mObjects.end(); ++i)
@@ -392,6 +428,12 @@ void MetadataFile::updateEntryLength(off_t offset, size_t newLength)
updateObj->length = newLength; updateObj->length = newLength;
} }
metadataObject::metadataObject()
{}
metadataObject::metadataObject(uint64_t _offset) : offset(_offset)
{}
} }

View File

@@ -18,14 +18,14 @@ namespace storagemanager
{ {
struct metadataObject { struct metadataObject {
metadataObject();
metadataObject(uint64_t offset); // so we can search mObjects by integer
uint64_t offset; uint64_t offset;
mutable uint64_t length; mutable uint64_t length;
mutable std::string key; mutable std::string key;
bool operator < (const metadataObject &b) const { return offset < b.offset; } bool operator < (const metadataObject &b) const { return offset < b.offset; }
}; };
class MetadataFile class MetadataFile
{ {
public: public:
@@ -36,10 +36,11 @@ class MetadataFile
~MetadataFile(); ~MetadataFile();
bool exists() const; bool exists() const;
void printObjects(); void printObjects() const;
int stat(struct stat *) const; int stat(struct stat *) const;
size_t getLength() const;
// returns the objects needed to update // returns the objects needed to update
std::vector<metadataObject> metadataRead(off_t offset, size_t length); std::vector<metadataObject> metadataRead(off_t offset, size_t length) const;
// updates the metadatafile with new object // updates the metadatafile with new object
int writeMetadata(const char *filename); int writeMetadata(const char *filename);
@@ -47,6 +48,7 @@ class MetadataFile
void updateEntry(off_t offset, const std::string &newName, size_t newLength); void updateEntry(off_t offset, const std::string &newName, size_t newLength);
void updateEntryLength(off_t offset, size_t newLength); void updateEntryLength(off_t offset, size_t newLength);
metadataObject addMetadataObject(const char *filename, size_t length); metadataObject addMetadataObject(const char *filename, size_t length);
void removeEntry(off_t offset);
// TBD: this may have to go; there may be no use case where only the uuid needs to change. // TBD: this may have to go; there may be no use case where only the uuid needs to change.
static std::string getNewKeyFromOldKey(const std::string &oldKey, size_t length=0); static std::string getNewKeyFromOldKey(const std::string &oldKey, size_t length=0);

View File

@@ -160,10 +160,9 @@ int Replicator::addJournalEntry(const char *filename, const uint8_t *data, off_t
return count; return count;
} }
int Replicator::remove(const char *filename, Flags flags) int Replicator::remove(const boost::filesystem::path &filename, Flags flags)
{ {
int ret = 0; int ret = 0;
boost::filesystem::path p(filename);
try try
{ {
@@ -177,9 +176,16 @@ int Replicator::remove(const char *filename, Flags flags)
return ret; return ret;
} }
int Replicator::updateMetadata(const char *filename, const MetadataFile &meta)
int Replicator::remove(const char *filename, Flags flags)
{ {
return 0; boost::filesystem::path p(filename);
return remove(p);
}
int Replicator::updateMetadata(const char *filename, MetadataFile &meta)
{
return meta.writeMetadata(filename);
} }
} }

View File

@@ -3,6 +3,7 @@
//#include "ThreadPool.h" //#include "ThreadPool.h"
#include "MetadataFile.h" #include "MetadataFile.h"
#include <boost/filesystem.hpp>
#include <sys/types.h> #include <sys/types.h>
#include <stdint.h> #include <stdint.h>
@@ -28,9 +29,10 @@ class Replicator
int addJournalEntry(const char *filename, const uint8_t *data, off_t offset, size_t length); int addJournalEntry(const char *filename, const uint8_t *data, off_t offset, size_t length);
int newObject(const char *filename, const uint8_t *data, size_t length); int newObject(const char *filename, const uint8_t *data, size_t length);
int remove(const char *key, Flags flags = NONE); int remove(const char *filename, Flags flags = NONE);
int remove(const boost::filesystem::path &file, Flags flags = NONE);
int updateMetadata(const char *filename, const MetadataFile &meta); int updateMetadata(const char *filename, MetadataFile &meta);
private: private:
Replicator(); Replicator();

View File

@@ -479,13 +479,75 @@ bool stattask()
return true; return true;
} }
bool IOCTruncate()
{
IOCoordinator *ioc = IOCoordinator::get();
CloudStorage *cs = CloudStorage::get();
LocalStorage *ls = dynamic_cast<LocalStorage *>(cs);
if (!ls)
{
cout << "IOCTruncate() currently requires using Local storage" << endl;
return true;
}
bf::path cachePath = ioc->getCachePath();
bf::path journalPath = ioc->getJournalPath();
bf::path metaPath = ioc->getMetadataPath();
bf::path cloudPath = ls->getPrefix();
// metaPath doesn't necessarily exist until a MetadataFile instance is created
bf::create_directories(metaPath);
/* start with one object in cloud storage
truncate past the end of the object
verify nothing changed & got success
truncate at 4000 bytes
verify everything sees the 'file' as 4000 bytes
- IOC + meta
truncate at 0 bytes
verify file now looks empty
verify the object was deleted
add 2 8k test objects and a journal against the second one
truncate @ 10000 bytes
verify all files still exist
truncate @ 6000 bytes, 2nd object & journal were deleted
truncate @ 0 bytes, verify no files are left
*/
makeTestMetadata((metaPath/"test-file.meta").string().c_str());
makeTestObject((cloudPath/testObjKey).string().c_str());
int err;
uint8_t buf[8192];
// Extending a file doesn't quite work yet, punting on it for now
err = ioc->truncate(testFile, 4000);
assert(!err);
MetadataFile meta(testFile);
assert(meta.getLength() == 4000);
// read the data, make sure there are only 4000 bytes
err = ioc->read(testFile, buf, 0, 8192);
assert(err == 4000);
err = ioc->read(testFile, buf, 4000, 1);
assert(err == 0);
return true;
}
bool truncatetask() bool truncatetask()
{ {
IOCoordinator *ioc = IOCoordinator::get();
Cache *cache = Cache::get();
bf::path metaPath = ioc->getMetadataPath();
const char *filename = "trunctest1"; const char *filename = "trunctest1";
::unlink(filename); // get the metafile created
int fd = ::open(filename, O_CREAT | O_RDWR, 0666); string metaFullName = (metaPath/filename).string() + ".meta";
assert(fd > 0); ::unlink(metaFullName.c_str());
scoped_closer f(fd); MetadataFile meta(filename);
uint8_t buf[1024]; uint8_t buf[1024];
truncate_cmd *cmd = (truncate_cmd *) buf; truncate_cmd *cmd = (truncate_cmd *) buf;
@@ -508,10 +570,12 @@ bool truncatetask()
assert(resp->header.payloadLen == 4); assert(resp->header.payloadLen == 4);
assert(resp->returnCode == 0); assert(resp->returnCode == 0);
struct stat statbuf; // reload the metadata, check that it is 1000 bytes
::stat(filename, &statbuf); meta = MetadataFile(filename);
assert(statbuf.st_size == 1000); assert(meta.getLength() == 1000);
::unlink(filename);
cache->reset();
::unlink(metaFullName.c_str());
cout << "truncate task OK" << endl; cout << "truncate task OK" << endl;
return true; return true;
} }
@@ -1072,6 +1136,10 @@ int main()
makeConnection(); makeConnection();
cout << "connected" << endl; cout << "connected" << endl;
scoped_closer sc1(serverSock), sc2(sessionSock), sc3(clientSock); scoped_closer sc1(serverSock), sc2(sessionSock), sc3(clientSock);
//IOCTruncate();
//return 0;
opentask(); opentask();
metadataUpdateTest(); metadataUpdateTest();
// requires 8K object size to test boundries // requires 8K object size to test boundries
@@ -1092,7 +1160,7 @@ int main()
appendtask(); appendtask();
unlinktask(); unlinktask();
stattask(); stattask();
truncatetask(); //truncatetask(); // currently waiting on IOC::write() to be completed.
listdirtask(); listdirtask();
pingtask(); pingtask();
copytask(); copytask();
@@ -1105,6 +1173,7 @@ int main()
s3storageTest1(); s3storageTest1();
IOCReadTest1(); IOCReadTest1();
IOCTruncate();
return 0; return 0;
} }