wsd: add min_time_between_save_ms config

This adds a new config entry to help tune
how often to save after the last save
request. This is used regardless of
the auto-save interval.

Change-Id: I58c291e69a63a3b98e72584817b408b54d9f80f1
Signed-off-by: Ashod Nakashian <ashod.nakashian@collabora.co.uk>
pull/5119/head
Ashod Nakashian 2022-04-23 10:04:03 -04:00 committed by Ashod Nakashian
parent ad19bb3055
commit 2d695a489e
4 changed files with 34 additions and 9 deletions

View File

@ -53,6 +53,7 @@
<limit_load_secs desc="Maximum number of seconds to wait for a document load to succeed. 0 for unlimited." type="uint" default="100">100</limit_load_secs>
<limit_store_failures desc="Maximum number of consecutive save-and-upload to storage failures when unloading the document. 0 for unlimited (not recommended)." type="uint" default="5">5</limit_store_failures>
<limit_convert_secs desc="Maximum number of seconds to wait for a document conversion to succeed. 0 for unlimited." type="uint" default="100">100</limit_convert_secs>
<min_time_between_saves_ms desc="Minimum number of milliseconds between saving the document on disk." type="uint" default="500">500</min_time_between_saves_ms>
<cleanup desc="Checks for resource consuming (bad) documents and kills associated kit process. A document is considered resource consuming (bad) if is in idle state for idle_time_secs period and memory usage passed limit_dirty_mem_mb or CPU usage passed limit_cpu_per" enable="true">
<cleanup_interval_ms desc="Interval between two checks" type="uint" default="10000">10000</cleanup_interval_ms>
<bad_behavior_period_secs desc="Minimum time period for a document to be in bad state before associated kit process is killed. If in this period the condition for bad document is not met once then this period is reset" type="uint" default="60">60</bad_behavior_period_secs>

View File

@ -1914,6 +1914,7 @@ void COOLWSD::innerInitialize(Application& self)
{ "per_document.limit_stack_mem_kb", "8000" },
{ "per_document.limit_virt_mem_mb", "0" },
{ "per_document.max_concurrency", "4" },
{ "per_document.min_time_between_saves_ms", "500" },
{ "per_document.batch_priority", "5" },
{ "per_document.pdf_resolution_dpi", "96" },
{ "per_document.redlining_as_comments", "false" },

View File

@ -2059,8 +2059,11 @@ void DocumentBroker::autoSaveAndStop(const std::string& reason)
}
}
static const auto minTimeBetweenSaves = std::chrono::milliseconds(
COOLWSD::getConfigValue<int>("per_document.min_time_between_saves_ms", 500));
// Don't hammer on saving.
if (!canStop && _saveManager.canSaveNow(std::chrono::milliseconds(500)))
if (!canStop && _saveManager.canSaveNow(minTimeBetweenSaves))
{
// Stop if there is nothing to save.
const bool possiblyModified = isPossiblyModified();
@ -2102,7 +2105,7 @@ void DocumentBroker::autoSaveAndStop(const std::string& reason)
LOG_TRC("Too soon to issue another save on ["
<< getDocKey() << "]: " << _saveManager.timeSinceLastSaveRequest()
<< " since last save request and " << _saveManager.timeSinceLastSaveRequest()
<< " since last save response");
<< " since last save response. Min time between saves: " << minTimeBetweenSaves);
}
if (canStop)

View File

@ -686,6 +686,7 @@ private:
RequestManager()
: _lastRequestTime(now())
, _lastResponseTime(now())
, _lastRequestDuration(0)
, _lastRequestFailureCount(0)
{
}
@ -711,11 +712,19 @@ private:
/// Sets the time the last response was received to now.
void markLastResponseTime() { _lastResponseTime = now(); }
void markLastResponseTime()
{
_lastResponseTime = now();
_lastRequestDuration = std::chrono::duration_cast<std::chrono::milliseconds>(
_lastResponseTime - _lastRequestTime);
}
/// Returns the time the last response was received.
std::chrono::steady_clock::time_point lastResponseTime() const { return _lastResponseTime; }
/// Returns the duration of the last request.
std::chrono::milliseconds lastRequestDuration() const { return _lastRequestDuration; }
/// How much time passed since the last response,
/// regardless of whether there is a newer request or not.
const std::chrono::milliseconds timeSinceLastResponse() const
@ -763,7 +772,10 @@ private:
/// The last time we received a response.
std::chrono::steady_clock::time_point _lastResponseTime;
/// Counts the number of previous request that failed.
/// The time we spent in the last request.
std::chrono::milliseconds _lastRequestDuration;
/// Counts the number of previous requests that failed.
/// Note that this is interpretted by the request in question.
/// For example, Core's Save operation turns 'false' for success
/// when the file is unmodified, but that is still a successful result.
@ -892,11 +904,21 @@ private:
return _request.timeSinceLastResponse();
}
/// Returns how long the last save took.
std::chrono::milliseconds lastSaveDuration() const
{
return _request.lastRequestDuration();
}
/// True if we aren't saving and the minimum time since last save has elapsed.
bool canSaveNow(std::chrono::milliseconds minTime) const
{
return !isSaving() && std::min(_request.timeSinceLastRequest(),
_request.timeSinceLastResponse()) >= minTime;
// Can't save if save is in progress, or when it the time elapsed
// since the last response, or request, hasn't been that long, or
// if it hasn't been longer than the time the last save took.
return !isSaving() &&
std::min(_request.timeSinceLastRequest(), _request.timeSinceLastResponse()) >=
std::max(minTime, lastSaveDuration());
}
void dumpState(std::ostream& os, const std::string& indent = "\n ")
@ -913,9 +935,7 @@ private:
<< "last save request: " << Util::getTimeForLog(now, lastSaveRequestTime());
os << indent
<< "last save response: " << Util::getTimeForLog(now, lastSaveResponseTime());
os << indent << "since last save request: " << timeSinceLastSaveRequest();
os << indent << "since last save response: " << timeSinceLastSaveResponse();
os << indent << "last save duration: " << lastSaveDuration();
os << indent
<< "file last modified time: " << Util::getTimeForLog(now, _lastModifiedTime);