Skip to content

Commit c2426bb

Browse files
committed
Refactor to put more trust in abstract-level state
Category: change
1 parent c177f3c commit c2426bb

File tree

1 file changed

+24
-60
lines changed

1 file changed

+24
-60
lines changed

binding.cc

Lines changed: 24 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -917,7 +917,6 @@ struct Iterator final : public BaseIterator {
917917
nexting_(false),
918918
isClosing_(false),
919919
ended_(false),
920-
closeWorker_(NULL),
921920
state_(state),
922921
ref_(NULL) {
923922
}
@@ -980,7 +979,6 @@ struct Iterator final : public BaseIterator {
980979
bool nexting_;
981980
bool isClosing_;
982981
bool ended_;
983-
BaseWorker* closeWorker_;
984982
unsigned char* state_;
985983
std::vector<Entry> cache_;
986984

@@ -996,7 +994,7 @@ struct Iterator final : public BaseIterator {
996994
static void env_cleanup_hook (void* arg) {
997995
Database* database = (Database*)arg;
998996

999-
// Do everything that db_close() does but synchronously. We're expecting that GC
997+
// Do everything that db.close() does but synchronously. We're expecting that GC
1000998
// did not (yet) collect the database because that would be a user mistake (not
1001999
// closing their db) made during the lifetime of the environment. That's different
10021000
// from an environment being torn down (like the main process or a worker thread)
@@ -1099,6 +1097,7 @@ NAPI_METHOD(db_open) {
10991097
NAPI_ARGV(3);
11001098
NAPI_DB_CONTEXT();
11011099
NAPI_ARGV_UTF8_NEW(location, 1);
1100+
NAPI_PROMISE();
11021101

11031102
napi_value options = argv[2];
11041103
const bool createIfMissing = BooleanProperty(env, options, "createIfMissing", true);
@@ -1116,8 +1115,6 @@ NAPI_METHOD(db_open) {
11161115

11171116
database->blockCache_ = leveldb::NewLRUCache(cacheSize);
11181117

1119-
NAPI_PROMISE();
1120-
11211118
OpenWorker* worker = new OpenWorker(
11221119
env, database, deferred, location,
11231120
createIfMissing, errorIfExists,
@@ -1159,36 +1156,15 @@ NAPI_METHOD(db_close) {
11591156
NAPI_DB_CONTEXT();
11601157
NAPI_PROMISE();
11611158

1159+
// AbstractLevel should not call _close() before iterators are closed
1160+
assert(database->iterators_.size() == 0);
1161+
11621162
CloseWorker* worker = new CloseWorker(env, database, deferred);
11631163

11641164
if (!database->HasPriorityWork()) {
11651165
worker->Queue(env);
1166-
return promise;
1167-
}
1168-
1169-
database->pendingCloseWorker_ = worker;
1170-
1171-
std::map<uint32_t, Iterator*> iterators = database->iterators_;
1172-
std::map<uint32_t, Iterator*>::iterator it;
1173-
1174-
for (it = iterators.begin(); it != iterators.end(); ++it) {
1175-
Iterator* iterator = it->second;
1176-
1177-
// TODO (v2): should no longer be necessary? Also not in abstract-level v1. But
1178-
// if it is, then find a cleaner solution than creating a whole bunch of throwaway promises.
1179-
if (!iterator->isClosing_ && !iterator->hasClosed_) {
1180-
// napi_value iteratorPromise;
1181-
// napi_deferred iteratorDeferred;
1182-
// NAPI_STATUS_THROWS(napi_create_promise(env, &iteratorDeferred, &iteratorPromise));
1183-
// CloseIteratorWorker* worker = new CloseIteratorWorker(env, iterator, iteratorPromise, iteratorDeferred);
1184-
// iterator->isClosing_ = true;
1185-
//
1186-
// if (iterator->nexting_) {
1187-
// iterator->closeWorker_ = worker;
1188-
// } else {
1189-
// worker->Queue(env);
1190-
// }
1191-
}
1166+
} else {
1167+
database->pendingCloseWorker_ = worker;
11921168
}
11931169

11941170
return promise;
@@ -1757,9 +1733,9 @@ NAPI_METHOD(iterator_seek) {
17571733
NAPI_ARGV(2);
17581734
NAPI_ITERATOR_CONTEXT();
17591735

1760-
if (iterator->isClosing_ || iterator->hasClosed_) {
1761-
NAPI_RETURN_UNDEFINED();
1762-
}
1736+
// AbstractIterator should not call _seek() after _close()
1737+
assert(!iterator->isClosing_);
1738+
assert(!iterator->hasClosed_);
17631739

17641740
leveldb::Slice target = ToSlice(env, argv[1]);
17651741
iterator->first_ = true;
@@ -1801,20 +1777,16 @@ NAPI_METHOD(iterator_close) {
18011777
NAPI_ITERATOR_CONTEXT();
18021778
NAPI_PROMISE();
18031779

1804-
if (!iterator->isClosing_ && !iterator->hasClosed_) {
1805-
CloseIteratorWorker* worker = new CloseIteratorWorker(env, iterator, deferred);
1806-
iterator->isClosing_ = true;
1780+
// AbstractIterator should not call _close() more than once
1781+
assert(!iterator->isClosing_);
1782+
assert(!iterator->hasClosed_);
18071783

1808-
if (iterator->nexting_) {
1809-
iterator->closeWorker_ = worker;
1810-
} else {
1811-
worker->Queue(env);
1812-
}
1813-
} else {
1814-
// TODO (v2): I think we can remove the isClosing_ checks
1815-
napi_value argv = CreateCodeError(env, "LEVEL_XYZ", "Should not happen?");
1816-
NAPI_STATUS_THROWS(napi_reject_deferred(env, deferred, argv));
1817-
}
1784+
// AbstractIterator should not call _close() while next() is in-progress
1785+
assert(!iterator->nexting_);
1786+
1787+
CloseIteratorWorker* worker = new CloseIteratorWorker(env, iterator, deferred);
1788+
iterator->isClosing_ = true;
1789+
worker->Queue(env);
18181790

18191791
return promise;
18201792
}
@@ -1864,15 +1836,7 @@ struct NextWorker final : public BaseWorker {
18641836
}
18651837

18661838
void DoFinally (napi_env env) override {
1867-
// clean up & handle the next/close state
18681839
iterator_->nexting_ = false;
1869-
1870-
// TODO (v2): check if still needed
1871-
if (iterator_->closeWorker_ != NULL) {
1872-
iterator_->closeWorker_->Queue(env);
1873-
iterator_->closeWorker_ = NULL;
1874-
}
1875-
18761840
BaseWorker::DoFinally(env);
18771841
}
18781842

@@ -1894,11 +1858,11 @@ NAPI_METHOD(iterator_nextv) {
18941858
NAPI_STATUS_THROWS(napi_get_value_uint32(env, argv[1], &size));
18951859
if (size == 0) size = 1;
18961860

1897-
if (iterator->isClosing_ || iterator->hasClosed_) {
1898-
// TODO (v2): test, or remove
1899-
napi_value argv = CreateCodeError(env, "LEVEL_ITERATOR_NOT_OPEN", "Iterator is not open");
1900-
NAPI_STATUS_THROWS(napi_reject_deferred(env, deferred, argv));
1901-
} else if (iterator->ended_) {
1861+
// AbstractIterator should not call _next() or _nextv() after _close()
1862+
assert(!iterator->isClosing_);
1863+
assert(!iterator->hasClosed_);
1864+
1865+
if (iterator->ended_) {
19021866
napi_value empty;
19031867
napi_create_array_with_length(env, 0, &empty);
19041868
napi_resolve_deferred(env, deferred, empty);

0 commit comments

Comments
 (0)