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:
Evan Tschannen 2019-04-23 18:26:02 -07:00 committed by GitHub
commit d8dbbe8186
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 56 additions and 24 deletions

View File

@ -2,7 +2,7 @@
Release Notes Release Notes
############# #############
6.1.0 6.1.3
===== =====
Features 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>`_ * 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>`_ * 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>`_ * 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 Fixes

View File

@ -1434,7 +1434,12 @@ public:
KeyValueStoreSQLite(std::string const& filename, UID logID, KeyValueStoreType type, bool checkChecksums, bool checkIntegrity); KeyValueStoreSQLite(std::string const& filename, UID logID, KeyValueStoreType type, bool checkChecksums, bool checkIntegrity);
~KeyValueStoreSQLite(); ~KeyValueStoreSQLite();
Future<Void> doClean(); struct SpringCleaningWorkPerformed {
int lazyDeletePages = 0;
int vacuumedPages = 0;
};
Future<SpringCleaningWorkPerformed> doClean();
void startReadThreads(); void startReadThreads();
private: private:
@ -1707,15 +1712,17 @@ private:
} }
struct SpringCleaningAction : TypedAction<Writer, SpringCleaningAction>, FastAllocated<SpringCleaningAction> { struct SpringCleaningAction : TypedAction<Writer, SpringCleaningAction>, FastAllocated<SpringCleaningAction> {
ThreadReturnPromise<Void> result; ThreadReturnPromise<SpringCleaningWorkPerformed> result;
virtual double getTimeEstimate() { return SERVER_KNOBS->SPRING_CLEANING_TIME_ESTIMATE; } 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) { void action(SpringCleaningAction& a) {
double s = now(); 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; SpringCleaningWorkPerformed workPerformed;
int vacuumedPages = 0;
double lazyDeleteTime = 0; double lazyDeleteTime = 0;
double vacuumTime = 0; double vacuumTime = 0;
@ -1725,8 +1732,13 @@ private:
loop { loop {
double begin = now(); 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 canDelete = !freeTableEmpty
bool canVacuum = !vacuumFinished && (now() < end || vacuumedPages < SERVER_KNOBS->SPRING_CLEANING_MIN_VACUUM_PAGES) && vacuumedPages < SERVER_KNOBS->SPRING_CLEANING_MAX_VACUUM_PAGES; && (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) { if(!canDelete && !canVacuum) {
break; break;
@ -1736,10 +1748,10 @@ private:
TEST(canVacuum); // SQLite lazy deletion when vacuuming is active TEST(canVacuum); // SQLite lazy deletion when vacuuming is active
TEST(!canVacuum); // SQLite lazy deletion when vacuuming is inactive 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) ; int pagesDeleted = cursor->lazyDelete(pagesToDelete) ;
freeTableEmpty = (pagesDeleted != pagesToDelete); freeTableEmpty = (pagesDeleted != pagesToDelete);
lazyDeletePages += pagesDeleted; workPerformed.lazyDeletePages += pagesDeleted;
lazyDeleteTime += now() - begin; lazyDeleteTime += now() - begin;
} }
else { else {
@ -1750,7 +1762,7 @@ private:
vacuumFinished = conn.vacuum(); vacuumFinished = conn.vacuum();
if(!vacuumFinished) { if(!vacuumFinished) {
++vacuumedPages; ++workPerformed.vacuumedPages;
} }
vacuumTime += now() - begin; vacuumTime += now() - begin;
@ -1761,19 +1773,19 @@ private:
freeListPages = conn.freePages(); freeListPages = conn.freePages();
TEST(lazyDeletePages > 0); // Pages lazily deleted TEST(workPerformed.lazyDeletePages > 0); // Pages lazily deleted
TEST(vacuumedPages > 0); // Pages vacuumed TEST(workPerformed.vacuumedPages > 0); // Pages vacuumed
TEST(vacuumTime > 0); // Time spent vacuuming TEST(vacuumTime > 0); // Time spent vacuuming
TEST(lazyDeleteTime > 0); // Time spent lazy deleting TEST(lazyDeleteTime > 0); // Time spent lazy deleting
++springCleaningStats.springCleaningCount; ++springCleaningStats.springCleaningCount;
springCleaningStats.lazyDeletePages += lazyDeletePages; springCleaningStats.lazyDeletePages += workPerformed.lazyDeletePages;
springCleaningStats.vacuumedPages += vacuumedPages; springCleaningStats.vacuumedPages += workPerformed.vacuumedPages;
springCleaningStats.springCleaningTime += now() - s; springCleaningStats.springCleaningTime += now() - s;
springCleaningStats.vacuumTime += vacuumTime; springCleaningStats.vacuumTime += vacuumTime;
springCleaningStats.lazyDeleteTime += lazyDeleteTime; springCleaningStats.lazyDeleteTime += lazyDeleteTime;
a.result.send(Void()); a.result.send(workPerformed);
++writesComplete; ++writesComplete;
if (g_network->isSimulated() && g_simulator.getCurrentProcess()->rebooting) if (g_network->isSimulated() && g_simulator.getCurrentProcess()->rebooting)
TraceEvent("SpringCleaningActionFinished", dbgid).detail("Elapsed", now()-s); 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 ) { ACTOR Future<Void> cleanPeriodically( KeyValueStoreSQLite* self ) {
wait(delayJittered(SERVER_KNOBS->SPRING_CLEANING_NO_ACTION_INTERVAL));
loop { loop {
wait( delayJittered(SERVER_KNOBS->CLEANING_INTERVAL) ); KeyValueStoreSQLite::SpringCleaningWorkPerformed workPerformed = wait(self->doClean());
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); readThreads->post(p);
return f; return f;
} }
Future<Void> KeyValueStoreSQLite::doClean() { Future<KeyValueStoreSQLite::SpringCleaningWorkPerformed> KeyValueStoreSQLite::doClean() {
++writesRequested; ++writesRequested;
auto p = new Writer::SpringCleaningAction; auto p = new Writer::SpringCleaningAction;
auto f = p->result.getFuture(); auto f = p->result.getFuture();

View File

@ -220,8 +220,11 @@ ServerKnobs::ServerKnobs(bool randomize, ClientKnobs* clientKnobs) {
init( SQLITE_FRAGMENT_MIN_SAVINGS, 0.20 ); init( SQLITE_FRAGMENT_MIN_SAVINGS, 0.20 );
// KeyValueStoreSqlite spring cleaning // KeyValueStoreSqlite spring cleaning
init( CLEANING_INTERVAL, 1.0 ); 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_TIME_ESTIMATE, .010 ); 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_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_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); 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);

View File

@ -169,8 +169,11 @@ public:
int SQLITE_CHUNK_SIZE_PAGES; int SQLITE_CHUNK_SIZE_PAGES;
// KeyValueStoreSqlite spring cleaning // KeyValueStoreSqlite spring cleaning
double CLEANING_INTERVAL; double SPRING_CLEANING_NO_ACTION_INTERVAL;
double SPRING_CLEANING_TIME_ESTIMATE; 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; double SPRING_CLEANING_VACUUMS_PER_LAZY_DELETE_PAGE;
int SPRING_CLEANING_MIN_LAZY_DELETE_PAGES; int SPRING_CLEANING_MIN_LAZY_DELETE_PAGES;
int SPRING_CLEANING_MAX_LAZY_DELETE_PAGES; int SPRING_CLEANING_MAX_LAZY_DELETE_PAGES;