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
|
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
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue