Use libdispatch for SCM status

Additionally the throttling has been improved. Previously we would delay a status fetch if it had been less than 3 seconds since the last request, but during this “penalty wait” more requests could still be submitted (in case of disk activity) and would be queued for later execution — now such requests are dropped.
This commit is contained in:
Allan Odgaard
2013-01-12 12:56:01 +01:00
parent 0f4fc14462
commit a222dfd805
4 changed files with 40 additions and 94 deletions

View File

@@ -1,6 +1,5 @@
#include "drivers/api.h"
#include "scm.h"
#include "server.h"
#include <io/path.h>
#include <cf/cf.h>
#include <oak/oak.h>
@@ -104,7 +103,6 @@ namespace scm
_did_setup = true;
}
status::type info_t::status (std::string const& path)
{
D(DBF_SCM, bug("%s\n", path.c_str()););
@@ -142,17 +140,50 @@ namespace scm
_callbacks.remove(cb);
}
static bool test_and_set (std::string const& key, bool flag)
{
static dispatch_queue_t queue = dispatch_queue_create("org.textmate.scm.coordination", DISPATCH_QUEUE_SERIAL);
static std::set<std::string> keys;
__block bool foundKey = false;
dispatch_sync(queue, ^{
auto it = keys.find(key);
foundKey = it != keys.end();
if(flag && !foundKey)
keys.insert(key);
else if(!flag && foundKey)
keys.erase(it);
});
return foundKey;
}
void info_t::callback (std::set<std::string> const& pathsChangedOnDisk)
{
D(DBF_SCM, bug("( %s )\n", text::join(pathsChangedOnDisk, ", ").c_str()););
background_status(_wc_path, _driver, _updated, _snapshot, &update_status);
}
void info_t::update_status (bool didUpdate, std::string const& path, fs::snapshot_t const& snapshot, scm::status_map_t const& newStatus)
{
if(!didUpdate)
if(test_and_set(_wc_path, true))
return;
static dispatch_queue_t queue = dispatch_queue_create("org.textmate.scm.status", DISPATCH_QUEUE_SERIAL);
dispatch_async(queue, ^{
double elapsed = oak::date_t::now() - _updated;
if(elapsed < 3)
usleep((3 - elapsed) * 1000000);
bool shouldCheck = _snapshot != fs::snapshot_t(_wc_path);
test_and_set(_wc_path, false);
if(shouldCheck)
{
scm::status_map_t status = _driver->status(_wc_path);
fs::snapshot_t snapshot(_wc_path);
dispatch_async(dispatch_get_main_queue(), ^{
update_status(_wc_path, snapshot, status);
});
}
});
}
void info_t::update_status (std::string const& path, fs::snapshot_t const& snapshot, scm::status_map_t const& newStatus)
{
auto it = cache().find(path);
if(it != cache().end())
{

View File

@@ -53,7 +53,7 @@ namespace scm
void callback (std::set<std::string> const& pathsChangedOnDisk);
oak::callbacks_t<callback_t> _callbacks;
static void update_status (bool didUpdate, std::string const& path, fs::snapshot_t const& snapshot, scm::status_map_t const& status);
static void update_status (std::string const& path, fs::snapshot_t const& snapshot, scm::status_map_t const& status);
};
PUBLIC info_ptr info (std::string const& dir);

View File

@@ -1,71 +0,0 @@
#include "drivers/api.h"
#include "server.h"
#include <io/path.h>
#include <oak/server.h>
namespace
{
struct payload_t
{
typedef payload_t* request_t;
payload_t (std::string const& path, scm::driver_t const* driver, oak::date_t const& updated, fs::snapshot_t const& snapshot, void(*callback)(bool, std::string const&, fs::snapshot_t const&, scm::status_map_t const&));
~payload_t ();
static bool handle_request (payload_t* request)
{
double elapsed = oak::date_t::now() - request->_updated;
if(elapsed < 3)
usleep((3 - elapsed) * 1000000);
if(request->_snapshot == fs::snapshot_t(request->_path))
return false;
request->_status = request->_driver->status(request->_path);
request->_snapshot = fs::snapshot_t(request->_path);
request->_updated = oak::date_t::now();
return true;
}
void handle_reply (bool didUpdate)
{
_callback(didUpdate, _path, _snapshot, _status);
delete this;
}
std::string const _path;
scm::driver_t const* _driver;
oak::date_t _updated;
fs::snapshot_t _snapshot;
scm::status_map_t _status;
void(*_callback)(bool, std::string const&, fs::snapshot_t const&, scm::status_map_t const&);
size_t _client_key;
};
static oak::server_t<payload_t>& server ()
{
static oak::server_t<payload_t> server;
return server;
}
payload_t::payload_t (std::string const& path, scm::driver_t const* driver, oak::date_t const& updated, fs::snapshot_t const& snapshot, void(*callback)(bool, std::string const&, fs::snapshot_t const&, scm::status_map_t const&)) : _path(path), _driver(driver), _updated(updated), _snapshot(snapshot), _callback(callback)
{
_client_key = server().register_client(this);
server().send_request(_client_key, this);
}
payload_t::~payload_t ()
{
server().unregister_client(_client_key);
}
}
namespace scm
{
void background_status (std::string const& path, driver_t const* driver, oak::date_t const& updated, fs::snapshot_t const& snapshot, void(*callback)(bool, std::string const&, fs::snapshot_t const&, scm::status_map_t const&))
{
new payload_t(path, driver, updated, snapshot, callback);
}
} /* scm */

View File

@@ -1,14 +0,0 @@
#ifndef SCM_SERVER_H_BND4Y51
#define SCM_SERVER_H_BND4Y51
#include "snapshot.h"
#include "scm.h"
#include <oak/misc.h>
namespace scm
{
PUBLIC void background_status (std::string const& path, driver_t const* driver, oak::date_t const& updated, fs::snapshot_t const& snapshot, void(*callback)(bool, std::string const&, fs::snapshot_t const&, scm::status_map_t const&));
} /* scm */
#endif /* end of include guard: SCM_SERVER_H_BND4Y51 */