Merge pull request #1485 from ajbeamon/speed-up-and-parameterize-spring-cleaning
Increase the frequency that lazy deletes are run. Add more parameters…
This commit is contained in:
commit
d8dbbe8186
|
@ -2,7 +2,7 @@
|
|||
Release Notes
|
||||
#############
|
||||
|
||||
6.1.0
|
||||
6.1.3
|
||||
=====
|
||||
|
||||
Features
|
||||
|
@ -47,6 +47,7 @@ Performance
|
|||
|
||||
* Increased the get read version batch size in the client. This change reduces the load on the proxies when doing many transactions with only a few operations per transaction. `(PR #1311) <https://github.com/apple/foundationdb/pull/1311>`_
|
||||
* Clients no longer attempt to connect to the master during recovery. `(PR #1317) <https://github.com/apple/foundationdb/pull/1317>`_
|
||||
* Increase the rate that deleted pages are made available for reuse in the SQLite storage engine. Rename and add knobs to provide more control over this process. [6.1.3] `(PR #1485) <https://github.com/apple/foundationdb/pull/1485>`_
|
||||
* SQLite page files now grow and shrink in chunks based on a knob which defaults to an effective chunk size of 4MB. [6.1.3] `(PR #1482) <https://github.com/apple/foundationdb/pull/1482>`_
|
||||
|
||||
Fixes
|
||||
|
|
|
@ -1434,7 +1434,12 @@ public:
|
|||
KeyValueStoreSQLite(std::string const& filename, UID logID, KeyValueStoreType type, bool checkChecksums, bool checkIntegrity);
|
||||
~KeyValueStoreSQLite();
|
||||
|
||||
Future<Void> doClean();
|
||||
struct SpringCleaningWorkPerformed {
|
||||
int lazyDeletePages = 0;
|
||||
int vacuumedPages = 0;
|
||||
};
|
||||
|
||||
Future<SpringCleaningWorkPerformed> doClean();
|
||||
void startReadThreads();
|
||||
|
||||
private:
|
||||
|
@ -1707,15 +1712,17 @@ private:
|
|||
}
|
||||
|
||||
struct SpringCleaningAction : TypedAction<Writer, SpringCleaningAction>, FastAllocated<SpringCleaningAction> {
|
||||
ThreadReturnPromise<Void> result;
|
||||
virtual double getTimeEstimate() { return SERVER_KNOBS->SPRING_CLEANING_TIME_ESTIMATE; }
|
||||
ThreadReturnPromise<SpringCleaningWorkPerformed> result;
|
||||
virtual double getTimeEstimate() {
|
||||
return std::max(SERVER_KNOBS->SPRING_CLEANING_LAZY_DELETE_TIME_ESTIMATE, SERVER_KNOBS->SPRING_CLEANING_VACUUM_TIME_ESTIMATE);
|
||||
}
|
||||
};
|
||||
void action(SpringCleaningAction& a) {
|
||||
double s = now();
|
||||
double end = now() + SERVER_KNOBS->SPRING_CLEANING_TIME_ESTIMATE;
|
||||
double lazyDeleteEnd = now() + SERVER_KNOBS->SPRING_CLEANING_LAZY_DELETE_TIME_ESTIMATE;
|
||||
double vacuumEnd = now() + SERVER_KNOBS->SPRING_CLEANING_VACUUM_TIME_ESTIMATE;
|
||||
|
||||
int lazyDeletePages = 0;
|
||||
int vacuumedPages = 0;
|
||||
SpringCleaningWorkPerformed workPerformed;
|
||||
|
||||
double lazyDeleteTime = 0;
|
||||
double vacuumTime = 0;
|
||||
|
@ -1725,8 +1732,13 @@ private:
|
|||
|
||||
loop {
|
||||
double begin = now();
|
||||
bool canDelete = !freeTableEmpty && (now() < end || lazyDeletePages < SERVER_KNOBS->SPRING_CLEANING_MIN_LAZY_DELETE_PAGES) && lazyDeletePages < SERVER_KNOBS->SPRING_CLEANING_MAX_LAZY_DELETE_PAGES;
|
||||
bool canVacuum = !vacuumFinished && (now() < end || vacuumedPages < SERVER_KNOBS->SPRING_CLEANING_MIN_VACUUM_PAGES) && vacuumedPages < SERVER_KNOBS->SPRING_CLEANING_MAX_VACUUM_PAGES;
|
||||
bool canDelete = !freeTableEmpty
|
||||
&& (now() < lazyDeleteEnd || workPerformed.lazyDeletePages < SERVER_KNOBS->SPRING_CLEANING_MIN_LAZY_DELETE_PAGES)
|
||||
&& workPerformed.lazyDeletePages < SERVER_KNOBS->SPRING_CLEANING_MAX_LAZY_DELETE_PAGES;
|
||||
|
||||
bool canVacuum = !vacuumFinished
|
||||
&& (now() < vacuumEnd || workPerformed.vacuumedPages < SERVER_KNOBS->SPRING_CLEANING_MIN_VACUUM_PAGES)
|
||||
&& workPerformed.vacuumedPages < SERVER_KNOBS->SPRING_CLEANING_MAX_VACUUM_PAGES;
|
||||
|
||||
if(!canDelete && !canVacuum) {
|
||||
break;
|
||||
|
@ -1736,10 +1748,10 @@ private:
|
|||
TEST(canVacuum); // SQLite lazy deletion when vacuuming is active
|
||||
TEST(!canVacuum); // SQLite lazy deletion when vacuuming is inactive
|
||||
|
||||
int pagesToDelete = std::max(1, std::min(SERVER_KNOBS->SPRING_CLEANING_LAZY_DELETE_BATCH_SIZE, SERVER_KNOBS->SPRING_CLEANING_MAX_LAZY_DELETE_PAGES - lazyDeletePages));
|
||||
int pagesToDelete = std::max(1, std::min(SERVER_KNOBS->SPRING_CLEANING_LAZY_DELETE_BATCH_SIZE, SERVER_KNOBS->SPRING_CLEANING_MAX_LAZY_DELETE_PAGES - workPerformed.lazyDeletePages));
|
||||
int pagesDeleted = cursor->lazyDelete(pagesToDelete) ;
|
||||
freeTableEmpty = (pagesDeleted != pagesToDelete);
|
||||
lazyDeletePages += pagesDeleted;
|
||||
workPerformed.lazyDeletePages += pagesDeleted;
|
||||
lazyDeleteTime += now() - begin;
|
||||
}
|
||||
else {
|
||||
|
@ -1750,7 +1762,7 @@ private:
|
|||
|
||||
vacuumFinished = conn.vacuum();
|
||||
if(!vacuumFinished) {
|
||||
++vacuumedPages;
|
||||
++workPerformed.vacuumedPages;
|
||||
}
|
||||
|
||||
vacuumTime += now() - begin;
|
||||
|
@ -1761,19 +1773,19 @@ private:
|
|||
|
||||
freeListPages = conn.freePages();
|
||||
|
||||
TEST(lazyDeletePages > 0); // Pages lazily deleted
|
||||
TEST(vacuumedPages > 0); // Pages vacuumed
|
||||
TEST(workPerformed.lazyDeletePages > 0); // Pages lazily deleted
|
||||
TEST(workPerformed.vacuumedPages > 0); // Pages vacuumed
|
||||
TEST(vacuumTime > 0); // Time spent vacuuming
|
||||
TEST(lazyDeleteTime > 0); // Time spent lazy deleting
|
||||
|
||||
++springCleaningStats.springCleaningCount;
|
||||
springCleaningStats.lazyDeletePages += lazyDeletePages;
|
||||
springCleaningStats.vacuumedPages += vacuumedPages;
|
||||
springCleaningStats.lazyDeletePages += workPerformed.lazyDeletePages;
|
||||
springCleaningStats.vacuumedPages += workPerformed.vacuumedPages;
|
||||
springCleaningStats.springCleaningTime += now() - s;
|
||||
springCleaningStats.vacuumTime += vacuumTime;
|
||||
springCleaningStats.lazyDeleteTime += lazyDeleteTime;
|
||||
|
||||
a.result.send(Void());
|
||||
a.result.send(workPerformed);
|
||||
++writesComplete;
|
||||
if (g_network->isSimulated() && g_simulator.getCurrentProcess()->rebooting)
|
||||
TraceEvent("SpringCleaningActionFinished", dbgid).detail("Elapsed", now()-s);
|
||||
|
@ -1852,9 +1864,22 @@ IKeyValueStore* keyValueStoreSQLite( std::string const& filename, UID logID, Key
|
|||
}
|
||||
|
||||
ACTOR Future<Void> cleanPeriodically( KeyValueStoreSQLite* self ) {
|
||||
wait(delayJittered(SERVER_KNOBS->SPRING_CLEANING_NO_ACTION_INTERVAL));
|
||||
loop {
|
||||
wait( delayJittered(SERVER_KNOBS->CLEANING_INTERVAL) );
|
||||
wait( self->doClean() );
|
||||
KeyValueStoreSQLite::SpringCleaningWorkPerformed workPerformed = wait(self->doClean());
|
||||
|
||||
double duration = std::numeric_limits<double>::max();
|
||||
if (workPerformed.lazyDeletePages >= SERVER_KNOBS->SPRING_CLEANING_LAZY_DELETE_BATCH_SIZE) {
|
||||
duration = std::min(duration, SERVER_KNOBS->SPRING_CLEANING_LAZY_DELETE_INTERVAL);
|
||||
}
|
||||
if (workPerformed.vacuumedPages > 0) {
|
||||
duration = std::min(duration, SERVER_KNOBS->SPRING_CLEANING_VACUUM_INTERVAL);
|
||||
}
|
||||
if (duration == std::numeric_limits<double>::max()) {
|
||||
duration = SERVER_KNOBS->SPRING_CLEANING_NO_ACTION_INTERVAL;
|
||||
}
|
||||
|
||||
wait(delayJittered(duration));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1960,7 +1985,7 @@ Future<Standalone<VectorRef<KeyValueRef>>> KeyValueStoreSQLite::readRange( KeyRa
|
|||
readThreads->post(p);
|
||||
return f;
|
||||
}
|
||||
Future<Void> KeyValueStoreSQLite::doClean() {
|
||||
Future<KeyValueStoreSQLite::SpringCleaningWorkPerformed> KeyValueStoreSQLite::doClean() {
|
||||
++writesRequested;
|
||||
auto p = new Writer::SpringCleaningAction;
|
||||
auto f = p->result.getFuture();
|
||||
|
|
|
@ -220,8 +220,11 @@ ServerKnobs::ServerKnobs(bool randomize, ClientKnobs* clientKnobs) {
|
|||
init( SQLITE_FRAGMENT_MIN_SAVINGS, 0.20 );
|
||||
|
||||
// KeyValueStoreSqlite spring cleaning
|
||||
init( CLEANING_INTERVAL, 1.0 );
|
||||
init( SPRING_CLEANING_TIME_ESTIMATE, .010 );
|
||||
init( SPRING_CLEANING_NO_ACTION_INTERVAL, 1.0 ); if( randomize && BUGGIFY ) SPRING_CLEANING_NO_ACTION_INTERVAL = g_random->coinflip() ? 0.1 : g_random->random01() * 5;
|
||||
init( SPRING_CLEANING_LAZY_DELETE_INTERVAL, 0.1 ); if( randomize && BUGGIFY ) SPRING_CLEANING_LAZY_DELETE_INTERVAL = g_random->coinflip() ? 1.0 : g_random->random01() * 5;
|
||||
init( SPRING_CLEANING_VACUUM_INTERVAL, 1.0 ); if( randomize && BUGGIFY ) SPRING_CLEANING_VACUUM_INTERVAL = g_random->coinflip() ? 0.1 : g_random->random01() * 5;
|
||||
init( SPRING_CLEANING_LAZY_DELETE_TIME_ESTIMATE, .010 ); if( randomize && BUGGIFY ) SPRING_CLEANING_LAZY_DELETE_TIME_ESTIMATE = g_random->random01() * 5;
|
||||
init( SPRING_CLEANING_VACUUM_TIME_ESTIMATE, .010 ); if( randomize && BUGGIFY ) SPRING_CLEANING_VACUUM_TIME_ESTIMATE = g_random->random01() * 5;
|
||||
init( SPRING_CLEANING_VACUUMS_PER_LAZY_DELETE_PAGE, 0.0 ); if( randomize && BUGGIFY ) SPRING_CLEANING_VACUUMS_PER_LAZY_DELETE_PAGE = g_random->coinflip() ? 1e9 : g_random->random01() * 5;
|
||||
init( SPRING_CLEANING_MIN_LAZY_DELETE_PAGES, 0 ); if( randomize && BUGGIFY ) SPRING_CLEANING_MIN_LAZY_DELETE_PAGES = g_random->randomInt(1, 100);
|
||||
init( SPRING_CLEANING_MAX_LAZY_DELETE_PAGES, 1e9 ); if( randomize && BUGGIFY ) SPRING_CLEANING_MAX_LAZY_DELETE_PAGES = g_random->coinflip() ? 0 : g_random->randomInt(1, 1e4);
|
||||
|
|
|
@ -169,8 +169,11 @@ public:
|
|||
int SQLITE_CHUNK_SIZE_PAGES;
|
||||
|
||||
// KeyValueStoreSqlite spring cleaning
|
||||
double CLEANING_INTERVAL;
|
||||
double SPRING_CLEANING_TIME_ESTIMATE;
|
||||
double SPRING_CLEANING_NO_ACTION_INTERVAL;
|
||||
double SPRING_CLEANING_LAZY_DELETE_INTERVAL;
|
||||
double SPRING_CLEANING_VACUUM_INTERVAL;
|
||||
double SPRING_CLEANING_LAZY_DELETE_TIME_ESTIMATE;
|
||||
double SPRING_CLEANING_VACUUM_TIME_ESTIMATE;
|
||||
double SPRING_CLEANING_VACUUMS_PER_LAZY_DELETE_PAGE;
|
||||
int SPRING_CLEANING_MIN_LAZY_DELETE_PAGES;
|
||||
int SPRING_CLEANING_MAX_LAZY_DELETE_PAGES;
|
||||
|
|
Loading…
Reference in New Issue