diff --git a/storage-manager/src/IOCoordinator.cpp b/storage-manager/src/IOCoordinator.cpp index c2e679f14..ea5b9ef15 100644 --- a/storage-manager/src/IOCoordinator.cpp +++ b/storage-manager/src/IOCoordinator.cpp @@ -402,15 +402,75 @@ ssize_t IOCoordinator::_write(const boost::filesystem::path &filename, const uin // there is no overlapping data, or data goes beyond end of last object while (dataRemaining > 0) { - off_t newObjectOffset = metadata.getMetadataNewObjectOffset(); + off_t currentEndofData = metadata.getMetadataNewObjectOffset(); + // count is 0 so first write is beyond current end of file. // offset is > than newObject.offset so we need to adjust offset for object // unless offset is beyond newObject.offset + objectSize then we need to write null data to this object - if (count == 0 && offset > newObjectOffset) + if (count == 0 && offset > currentEndofData) { + // First lets fill the last object with null data + objects = metadata.metadataRead(currentEndofData,1); + if (objects.size() == 1) + { + // last objeect needs data + metadataObject lastObject = objects[0]; + uint64_t nullJournalSize = (objectSize - lastObject.length); + uint8_t nullData[nullJournalSize]; + memset(nullData,0,nullJournalSize); + err = replicator->addJournalEntry((firstDir/lastObject.key),nullData,lastObject.length,nullJournalSize); + if (err < 0) + { + l_errno = errno; + replicator->updateMetadata(metadata); + //log error and abort + logger->log(LOG_ERR,"IOCoordinator::write(): Failed addJournalEntry -- NullData. Journal file likely has partially written data and incorrect metadata."); + errno = l_errno; + return -1; + } + else if ((uint)err < nullJournalSize) + { + dataRemaining -= err; + count += err; + iocBytesWritten += err; + if ((err + lastObject.length) > lastObject.length) + metadata.updateEntryLength(lastObject.offset, (err + lastObject.length)); + cache->newJournalEntry(firstDir, err+JOURNAL_ENTRY_HEADER_SIZE); + synchronizer->newJournalEntry(firstDir, lastObject.key, err+JOURNAL_ENTRY_HEADER_SIZE); + replicator->updateMetadata(metadata); + //logger->log(LOG_ERR,"IOCoordinator::write(): addJournalEntry incomplete write, %u of %u bytes written.",count,length); + return count; + } + metadata.updateEntryLength(lastObject.offset, (nullJournalSize + lastObject.length)); + cache->newJournalEntry(firstDir, nullJournalSize+JOURNAL_ENTRY_HEADER_SIZE); + synchronizer->newJournalEntry(firstDir, lastObject.key, nullJournalSize+JOURNAL_ENTRY_HEADER_SIZE); + currentEndofData += nullJournalSize; + iocBytesWritten += nullJournalSize + JOURNAL_ENTRY_HEADER_SIZE; + } + // dd we need to do some full null data objects + while ((currentEndofData + (off_t)objectSize) <= offset) + { + metadataObject nullObject = metadata.addMetadataObject(filename,objectSize); + err = replicator->newNullObject((firstDir/nullObject.key),objectSize); + if (err < 0) + { + //log error and abort + l_errno = errno; + logger->log(LOG_ERR,"IOCoordinator::write(): Failed newNullObject."); + errno = l_errno; + if (count == 0) // if no data has been written yet, it's safe to return -1 here. + return -1; + goto out; + } + cache->newObject(firstDir, nullObject.key,objectSize); + newObjectKeys.push_back(nullObject.key); + iocBytesWritten += objectSize; + currentEndofData += objectSize; + } + //this is starting beyond last object in metadata //figure out if the offset is in this object - objectOffset = offset - newObjectOffset; + objectOffset = offset - currentEndofData; writeLength = min((objectSize - objectOffset),dataRemaining); } else @@ -423,9 +483,7 @@ ssize_t IOCoordinator::_write(const boost::filesystem::path &filename, const uin // objectOffset is 0 unless the write starts beyond the end of data // in that case need to add the null data to cachespace //cache->makeSpace(writeLength + objectOffset); - metadataObject newObject = metadata.addMetadataObject(filename,(writeLength + objectOffset)); - // send to replicator err = replicator->newObject((firstDir/newObject.key),&data[count],objectOffset,writeLength); //assert((uint) err == writeLength); diff --git a/storage-manager/src/MetadataFile.cpp b/storage-manager/src/MetadataFile.cpp index 4f549bad1..e79a88be6 100644 --- a/storage-manager/src/MetadataFile.cpp +++ b/storage-manager/src/MetadataFile.cpp @@ -295,7 +295,7 @@ metadataObject MetadataFile::addMetadataObject(const boost::filesystem::path &fi if (!objects.empty()) { auto &lastObject = objects.back().second; - addObject.offset = lastObject.get("offset") + lastObject.get("length"); + addObject.offset = lastObject.get("offset") + mpConfig->mObjectSize; } addObject.length = length; diff --git a/storage-manager/src/Replicator.cpp b/storage-manager/src/Replicator.cpp index 31e18c7dd..6e387726c 100644 --- a/storage-manager/src/Replicator.cpp +++ b/storage-manager/src/Replicator.cpp @@ -143,6 +143,17 @@ int Replicator::newObject(const boost::filesystem::path &filename, const uint8_t return count; } +int Replicator::newNullObject(const boost::filesystem::path &filename,size_t length ) +{ + int fd, err; + string objectFilename = msCachePath + "/" + filename.string(); + + OPEN(objectFilename.c_str(), O_WRONLY | O_CREAT); + err = ftruncate(fd,length); + + return err; +} + int Replicator::addJournalEntry(const boost::filesystem::path &filename, const uint8_t *data, off_t offset, size_t length) { int fd, err; diff --git a/storage-manager/src/Replicator.h b/storage-manager/src/Replicator.h index 6af51a1b7..d4a6942f2 100644 --- a/storage-manager/src/Replicator.h +++ b/storage-manager/src/Replicator.h @@ -48,6 +48,8 @@ class Replicator int addJournalEntry(const boost::filesystem::path &filename, const uint8_t *data, off_t offset, size_t length); int newObject(const boost::filesystem::path &filename, const uint8_t *data, off_t offset, size_t length); + int newNullObject(const boost::filesystem::path &filename,size_t length ); + int remove(const boost::filesystem::path &file, Flags flags = NONE); int updateMetadata(MetadataFile &meta); diff --git a/storage-manager/src/unit_tests.cpp b/storage-manager/src/unit_tests.cpp index 27d010bf5..8a989d85c 100644 --- a/storage-manager/src/unit_tests.cpp +++ b/storage-manager/src/unit_tests.cpp @@ -1316,7 +1316,9 @@ void IOCReadTest1() string metaFilename = (metaPath/metaTestFile).string() + ".meta"; boost::scoped_array data(new uint8_t[1<<20]); + memset(data.get(), 0, 1<<20); + int err; err = ioc->read(testFile, data.get(), 0, 1<<20); assert(err < 0); @@ -1348,6 +1350,9 @@ void IOCReadTest1() for (; i < (1<<20)/4; i++) assert(data32[i] == 0); + err = ioc->read(testFile, data.get(), 9000, 4000); + assert(err==0); + cache->reset(); err = ioc->unlink(testFile); assert(err>= 0); @@ -1628,8 +1633,14 @@ int main(int argc, char* argv[]) //Case 3 write spans 2 journal objects metadataJournalTest((8*sizeKB),(4*sizeKB)); //Case 4 write starts object1 ends object3 - metadataJournalTest((10*sizeKB),(7*sizeKB)); - //Case 5 write starts in new object at offset >0 + metadataJournalTest((16*sizeKB),(7*sizeKB)); + //Case 5 write starts in new object at 0 offset after null objects + metadataJournalTest((8*sizeKB),(32*sizeKB)); + // overwrite null objects + metadataJournalTest((10*sizeKB),(40*sizeKB)); + metadataJournalTest((8*sizeKB),(24*sizeKB)); + // overwrite whole file and create new objects + metadataJournalTest((96*sizeKB),(0)); //append test // first one appends file to end of 8K object @@ -1668,8 +1679,9 @@ int main(int argc, char* argv[]) metadataJournalTestCleanup(); (Cache::get())->shutdown(); - delete (IOCoordinator::get()); + delete (Synchronizer::get()); delete (Cache::get()); + delete (IOCoordinator::get()); return 0; }