implement getFilesChangedSince

Summary:
This is pretty straightforward; we just walk back until we hit the
boundary with the requested JournalPosition.sequenceNumber

Reviewed By: simpkins

Differential Revision: D3872970

fbshipit-source-id: 1405f05957346d7ac513070f0407a477548aff1d
This commit is contained in:
Wez Furlong 2016-09-19 12:48:15 -07:00 committed by Michael Bolin
parent 82c57b2bf8
commit 8f4373571b
4 changed files with 99 additions and 6 deletions

View File

@ -7,10 +7,11 @@
# LICENSE file in the root directory of this source tree. An additional grant
# of patent rights can be found in the PATENTS file in the same directory.
import errno
import os
import stat
from .lib import testcase
from facebook.eden import EdenService
@testcase.eden_repo_test
class MaterializedQueryTest:
@ -42,9 +43,26 @@ class MaterializedQueryTest:
self.assertEqual(1, pos.sequenceNumber)
self.assertNotEqual(0, pos.mountGeneration)
def test_addFile(self):
changed = self.client.getFilesChangedSince(self.mount, pos)
self.assertEqual(0, len(changed.paths))
self.assertEqual(pos, changed.fromPosition)
self.assertEqual(pos, changed.toPosition)
def test_invalidProcessGeneration(self):
# Get a candidate position
pos = self.client.getCurrentJournalPosition(self.mount)
self.assertEqual(1, pos.sequenceNumber)
# poke the generation to a value that will never manifest in practice
pos.mountGeneration = 0
with self.assertRaises(EdenService.EdenError) as context:
self.client.getFilesChangedSince(self.mount, pos)
self.assertEqual(errno.ERANGE, context.exception.errorCode,
msg='Must return ERANGE')
def test_addFile(self):
initial_pos = self.client.getCurrentJournalPosition(self.mount)
self.assertEqual(1, initial_pos.sequenceNumber)
name = os.path.join(self.mount, 'overlaid')
with open(name, 'w+') as f:
@ -52,13 +70,25 @@ class MaterializedQueryTest:
self.assertEqual(2, pos.sequenceNumber,
msg='creating a file bumps the journal')
changed = self.client.getFilesChangedSince(self.mount, initial_pos)
self.assertEqual(['overlaid'], changed.paths)
self.assertEqual(initial_pos.sequenceNumber + 1,
changed.fromPosition.sequenceNumber,
msg='changes start AFTER initial_pos')
f.write('NAME!\n')
pos = self.client.getCurrentJournalPosition(self.mount)
self.assertEqual(3, pos.sequenceNumber, msg='writing bumps the journal')
pos_after_overlaid = self.client.getCurrentJournalPosition(self.mount)
self.assertEqual(3, pos_after_overlaid.sequenceNumber,
msg='writing bumps the journal')
changed = self.client.getFilesChangedSince(self.mount, initial_pos)
self.assertEqual(['overlaid'], changed.paths)
self.assertEqual(initial_pos.sequenceNumber + 1,
changed.fromPosition.sequenceNumber,
msg='changes start AFTER initial_pos')
info = self.client.getMaterializedEntries(self.mount)
self.assertEqual(pos, info.currentPosition,
self.assertEqual(pos_after_overlaid, info.currentPosition,
msg='consistent with getCurrentJournalPosition')
items = info.fileInfo
@ -81,6 +111,13 @@ class MaterializedQueryTest:
self.assertEqual(4, pos.sequenceNumber,
msg='appending bumps the journal')
changed = self.client.getFilesChangedSince(
self.mount, pos_after_overlaid)
self.assertEqual(['adir/file'], changed.paths)
self.assertEqual(pos_after_overlaid.sequenceNumber + 1,
changed.fromPosition.sequenceNumber,
msg='changes start AFTER pos_after_overlaid')
info = self.client.getMaterializedEntries(self.mount)
self.assertEqual(pos, info.currentPosition,
msg='consistent with getCurrentJournalPosition')

View File

@ -12,6 +12,7 @@
#include <boost/polymorphic_cast.hpp>
#include <folly/FileUtil.h>
#include <folly/String.h>
#include <unordered_set>
#include "EdenServer.h"
#include "eden/fs/config/ClientConfig.h"
#include "eden/fs/inodes/EdenMount.h"
@ -328,6 +329,55 @@ void EdenServiceHandler::getCurrentJournalPosition(
out.snapshotHash = StringPiece(latest->toHash.getBytes()).str();
}
void EdenServiceHandler::getFilesChangedSince(
FileDelta& out,
std::unique_ptr<std::string> mountPoint,
std::unique_ptr<JournalPosition> fromPosition) {
auto edenMount = server_->getMount(*mountPoint);
auto inodeDispatcher = edenMount->getMountPoint()->getDispatcher();
auto delta = edenMount->getJournal().rlock()->getLatest();
if (fromPosition->mountGeneration != edenMount->getMountGeneration()) {
throw EdenError(
apache::thrift::FragileConstructor(),
"fromPosition.mountGeneration does not match the current "
"mountGeneration. "
"You need to compute a new basis for delta queries.",
ERANGE);
}
std::unordered_set<RelativePath> changedFiles;
out.toPosition.sequenceNumber = delta->toSequence;
out.toPosition.snapshotHash = StringPiece(delta->toHash.getBytes()).str();
out.toPosition.mountGeneration = edenMount->getMountGeneration();
out.fromPosition = out.toPosition;
while (delta) {
if (delta->toSequence <= fromPosition->sequenceNumber) {
// We've reached the end of the interesting section
break;
}
changedFiles.insert(
delta->changedFilesInOverlay.begin(),
delta->changedFilesInOverlay.end());
out.fromPosition.sequenceNumber = delta->fromSequence;
out.fromPosition.snapshotHash =
StringPiece(delta->fromHash.getBytes()).str();
out.fromPosition.mountGeneration = edenMount->getMountGeneration();
delta = delta->previous;
}
for (auto& path : changedFiles) {
out.paths.emplace_back(path.stringPiece().str());
}
}
void EdenServiceHandler::shutdown() {
server_->stop();
}

View File

@ -56,6 +56,11 @@ class EdenServiceHandler : virtual public EdenServiceSvIf,
JournalPosition& out,
std::unique_ptr<std::string> mountPoint) override;
void getFilesChangedSince(
FileDelta& out,
std::unique_ptr<std::string> mountPoint,
std::unique_ptr<JournalPosition> fromPosition) override;
/**
* When this Thrift handler is notified to shutdown, it notifies the
* EdenServer to shut down, as well.

View File

@ -143,6 +143,7 @@ service EdenService extends fb303.FacebookService {
FileDelta getFilesChangedSince(
1: string mountPoint,
2: JournalPosition fromPosition)
throws (1: EdenError ex)
/** Returns a subset of the stat() information for a list of paths.
* The returned list of information corresponds to the input list of