This is an automated email from the ASF dual-hosted git repository.

zhaoc pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-doris.git


The following commit(s) were added to refs/heads/master by this push:
     new 3690f3e  Add rowset state (#2691)
3690f3e is described below

commit 3690f3e917c4aea8127d1e02acf42a4174cdc44d
Author: kangpinghuang <[email protected]>
AuthorDate: Fri Jan 10 14:17:57 2020 +0800

    Add rowset state (#2691)
    
    1. add rowset state to rowset
    2. add close api to rowset to release resources
    issue: #2665
---
 be/src/olap/compaction.cpp                 |   1 +
 be/src/olap/olap_define.h                  |   3 +-
 be/src/olap/rowset/alpha_rowset.cpp        |   7 +-
 be/src/olap/rowset/alpha_rowset.h          |   6 +-
 be/src/olap/rowset/alpha_rowset_reader.cpp |   3 +
 be/src/olap/rowset/beta_rowset.cpp         |  11 ++-
 be/src/olap/rowset/beta_rowset.h           |   9 ++-
 be/src/olap/rowset/beta_rowset_reader.cpp  |   2 +
 be/src/olap/rowset/beta_rowset_reader.h    |   4 +-
 be/src/olap/rowset/rowset.cpp              |  25 +++++-
 be/src/olap/rowset/rowset.h                | 126 ++++++++++++++++++++++++++++-
 be/src/olap/storage_engine.cpp             |   3 +-
 12 files changed, 181 insertions(+), 19 deletions(-)

diff --git a/be/src/olap/compaction.cpp b/be/src/olap/compaction.cpp
index 418b695..dd21b24 100644
--- a/be/src/olap/compaction.cpp
+++ b/be/src/olap/compaction.cpp
@@ -175,6 +175,7 @@ OLAPStatus Compaction::gc_unused_rowsets() {
     for (auto& rowset : _input_rowsets) {
         storage_engine->add_unused_rowset(rowset);
     }
+    _input_rowsets.clear();
     return OLAP_SUCCESS;
 }
 
diff --git a/be/src/olap/olap_define.h b/be/src/olap/olap_define.h
index 78d327b..ed4b0fd 100644
--- a/be/src/olap/olap_define.h
+++ b/be/src/olap/olap_define.h
@@ -369,7 +369,8 @@ enum OLAPStatus {
     OLAP_ERR_ROWSET_INVALID = -3108,
     OLAP_ERR_ROWSET_LOAD_FAILED = -3109,
     OLAP_ERR_ROWSET_READER_INIT = -3110,
-    OLAP_ERR_ROWSET_READ_FAILED = -3111
+    OLAP_ERR_ROWSET_READ_FAILED = -3111,
+    OLAP_ERR_ROWSET_INVALID_STATE_TRANSITION = -3112
 };
 
 enum ColumnFamilyIndex {
diff --git a/be/src/olap/rowset/alpha_rowset.cpp 
b/be/src/olap/rowset/alpha_rowset.cpp
index 4f419a3..9e84b3e 100644
--- a/be/src/olap/rowset/alpha_rowset.cpp
+++ b/be/src/olap/rowset/alpha_rowset.cpp
@@ -30,7 +30,7 @@ AlphaRowset::AlphaRowset(const TabletSchema* schema,
     : Rowset(schema, std::move(rowset_path), std::move(rowset_meta)) {
 }
 
-OLAPStatus AlphaRowset::do_load_once(bool use_cache) {
+OLAPStatus AlphaRowset::do_load(bool use_cache) {
     for (auto& segment_group: _segment_groups) {
         // validate segment group
         if (segment_group->validate() != OLAP_SUCCESS) {
@@ -52,14 +52,15 @@ OLAPStatus AlphaRowset::do_load_once(bool use_cache) {
 }
 
 OLAPStatus AlphaRowset::create_reader(std::shared_ptr<RowsetReader>* result) {
-    RETURN_NOT_OK(load());
     result->reset(new AlphaRowsetReader(
         _schema->num_rows_per_row_block(), 
std::static_pointer_cast<AlphaRowset>(shared_from_this())));
     return OLAP_SUCCESS;
 }
 
 OLAPStatus AlphaRowset::remove() {
-    LOG(INFO) << "begin to remove files in rowset " << unique_id();
+    LOG(INFO) << "begin to remove files in rowset " << unique_id()
+            << ", version:" << start_version() << "-" << end_version()
+            << ", tabletid:" << _rowset_meta->tablet_id();
     for (auto segment_group : _segment_groups) {
         bool ret = segment_group->delete_all_files();
         if (!ret) {
diff --git a/be/src/olap/rowset/alpha_rowset.h 
b/be/src/olap/rowset/alpha_rowset.h
index 35e44f4..1d4f8a9 100644
--- a/be/src/olap/rowset/alpha_rowset.h
+++ b/be/src/olap/rowset/alpha_rowset.h
@@ -73,11 +73,13 @@ protected:
     AlphaRowset(const TabletSchema* schema,
                 std::string rowset_path,
                 RowsetMetaSharedPtr rowset_meta);
-
+    
     // init segment groups
     OLAPStatus init() override;
 
-    OLAPStatus do_load_once(bool use_cache) override ;
+    OLAPStatus do_load(bool use_cache) override;
+
+    void do_close() override { }
 
     // add custom logic when rowset is published
     void make_visible_extra(Version version, VersionHash version_hash) 
override;
diff --git a/be/src/olap/rowset/alpha_rowset_reader.cpp 
b/be/src/olap/rowset/alpha_rowset_reader.cpp
index 9460601..278576a 100644
--- a/be/src/olap/rowset/alpha_rowset_reader.cpp
+++ b/be/src/olap/rowset/alpha_rowset_reader.cpp
@@ -29,13 +29,16 @@ AlphaRowsetReader::AlphaRowsetReader(
         
_alpha_rowset_meta(std::static_pointer_cast<AlphaRowsetMeta>(_rowset->rowset_meta()).get()),
         _segment_groups(_rowset->_segment_groups),
         _key_range_size(0) {
+    _rowset->aquire();
 }
 
 AlphaRowsetReader::~AlphaRowsetReader() {
     delete _dst_cursor;
+    _rowset->release();
 }
 
 OLAPStatus AlphaRowsetReader::init(RowsetReaderContext* read_context) {
+    RETURN_NOT_OK(_rowset->load());
     if (read_context == nullptr) {
         return OLAP_ERR_INIT_FAILED;
     }
diff --git a/be/src/olap/rowset/beta_rowset.cpp 
b/be/src/olap/rowset/beta_rowset.cpp
index 204e581..6207034 100644
--- a/be/src/olap/rowset/beta_rowset.cpp
+++ b/be/src/olap/rowset/beta_rowset.cpp
@@ -45,7 +45,7 @@ OLAPStatus BetaRowset::init() {
 }
 
 // `use_cache` is ignored because beta rowset doesn't support fd cache now
-OLAPStatus BetaRowset::do_load_once(bool /*use_cache*/) {
+OLAPStatus BetaRowset::do_load(bool /*use_cache*/) {
     // Open all segments under the current rowset
     for (int seg_id = 0; seg_id < num_segments(); ++seg_id) {
         std::string seg_path = segment_file_path(_rowset_path, rowset_id(), 
seg_id);
@@ -62,7 +62,6 @@ OLAPStatus BetaRowset::do_load_once(bool /*use_cache*/) {
 }
 
 OLAPStatus BetaRowset::create_reader(RowsetReaderSharedPtr* result) {
-    RETURN_NOT_OK(load());
     // NOTE: We use std::static_pointer_cast for performance
     result->reset(new 
BetaRowsetReader(std::static_pointer_cast<BetaRowset>(shared_from_this())));
     return OLAP_SUCCESS;
@@ -79,7 +78,9 @@ OLAPStatus BetaRowset::split_range(const RowCursor& start_key,
 
 OLAPStatus BetaRowset::remove() {
     // TODO should we close and remove all segment reader first?
-    LOG(INFO) << "begin to remove files in rowset " << unique_id();
+    LOG(INFO) << "begin to remove files in rowset " << unique_id()
+            << ", version:" << start_version() << "-" << end_version()
+            << ", tabletid:" << _rowset_meta->tablet_id();
     bool success = true;
     for (int i = 0; i < num_segments(); ++i) {
         std::string path = segment_file_path(_rowset_path, rowset_id(), i);
@@ -99,6 +100,10 @@ OLAPStatus BetaRowset::remove() {
     return OLAP_SUCCESS;
 }
 
+void BetaRowset::do_close() {
+    _segments.clear();
+}
+
 OLAPStatus BetaRowset::link_files_to(const std::string& dir, RowsetId 
new_rowset_id) {
     for (int i = 0; i < num_segments(); ++i) {
         std::string dst_link_path = segment_file_path(dir, new_rowset_id, i);
diff --git a/be/src/olap/rowset/beta_rowset.h b/be/src/olap/rowset/beta_rowset.h
index 3c6955e..f37d213 100644
--- a/be/src/olap/rowset/beta_rowset.h
+++ b/be/src/olap/rowset/beta_rowset.h
@@ -36,11 +36,11 @@ class BetaRowset : public Rowset {
 public:
     virtual ~BetaRowset();
 
+    OLAPStatus create_reader(RowsetReaderSharedPtr* result) override;
+
     static std::string segment_file_path(
             const std::string& segment_dir, const RowsetId& rowset_id, int 
segment_id);
 
-    OLAPStatus create_reader(RowsetReaderSharedPtr* result) override;
-
     OLAPStatus split_range(const RowCursor& start_key,
                            const RowCursor& end_key,
                            uint64_t request_block_row_count,
@@ -66,9 +66,12 @@ protected:
                std::string rowset_path,
                RowsetMetaSharedPtr rowset_meta);
 
+    // init segment groups
     OLAPStatus init() override;
 
-    OLAPStatus do_load_once(bool use_cache) override ;
+    OLAPStatus do_load(bool use_cache) override;
+
+    void do_close() override;
 
 private:
     friend class BetaRowsetReader;
diff --git a/be/src/olap/rowset/beta_rowset_reader.cpp 
b/be/src/olap/rowset/beta_rowset_reader.cpp
index e161c8d..4e52eb0 100644
--- a/be/src/olap/rowset/beta_rowset_reader.cpp
+++ b/be/src/olap/rowset/beta_rowset_reader.cpp
@@ -28,9 +28,11 @@ namespace doris {
 
 BetaRowsetReader::BetaRowsetReader(BetaRowsetSharedPtr rowset)
     : _rowset(std::move(rowset)), _stats(&_owned_stats) {
+    _rowset->aquire();
 }
 
 OLAPStatus BetaRowsetReader::init(RowsetReaderContext* read_context) {
+    RETURN_NOT_OK(_rowset->load());
     _context = read_context;
     if (_context->stats != nullptr) {
         // schema change/compaction should use owned_stats
diff --git a/be/src/olap/rowset/beta_rowset_reader.h 
b/be/src/olap/rowset/beta_rowset_reader.h
index 8afdcb1..ae5b687 100644
--- a/be/src/olap/rowset/beta_rowset_reader.h
+++ b/be/src/olap/rowset/beta_rowset_reader.h
@@ -31,7 +31,9 @@ class BetaRowsetReader : public RowsetReader {
 public:
     explicit BetaRowsetReader(BetaRowsetSharedPtr rowset);
 
-    ~BetaRowsetReader() override = default;
+    ~BetaRowsetReader() override {
+        _rowset->release();
+    }
 
     OLAPStatus init(RowsetReaderContext* read_context) override;
 
diff --git a/be/src/olap/rowset/rowset.cpp b/be/src/olap/rowset/rowset.cpp
index 7ca47ee..c30653d 100644
--- a/be/src/olap/rowset/rowset.cpp
+++ b/be/src/olap/rowset/rowset.cpp
@@ -24,7 +24,9 @@ Rowset::Rowset(const TabletSchema *schema,
                RowsetMetaSharedPtr rowset_meta)
         : _schema(schema),
          _rowset_path(std::move(rowset_path)),
-         _rowset_meta(std::move(rowset_meta)) {
+         _rowset_meta(std::move(rowset_meta)),
+         _refs_by_reader(0),
+         _rowset_state_machine(RowsetStateMachine()) {
 
     _is_pending = !_rowset_meta->has_version();
     if (_is_pending) {
@@ -36,7 +38,26 @@ Rowset::Rowset(const TabletSchema *schema,
 }
 
 OLAPStatus Rowset::load(bool use_cache) {
-    return _load_once.call([this, use_cache] { return do_load_once(use_cache); 
});
+    // if the state is ROWSET_UNLOADING it means close() is called
+    // and the rowset is already loaded, and the resource is not closed yet.
+    if (_rowset_state_machine.rowset_state() == ROWSET_LOADED) {
+        return OLAP_SUCCESS;
+    }
+    {
+        // before lock, if rowset state is ROWSET_UNLOADING, maybe it is doing 
do_close in release
+        std::lock_guard<std::mutex> load_lock(_lock);
+        // after lock, if rowset state is ROWSET_UNLOADING, it is ok to return
+        if (_rowset_state_machine.rowset_state() == ROWSET_UNLOADED) {
+            // first do load, then change the state
+            RETURN_NOT_OK(do_load(use_cache));
+            RETURN_NOT_OK(_rowset_state_machine.on_load());
+        }
+    }
+    // load is done
+    LOG(INFO) << "rowset is loaded. rowset version:" << start_version() << "-" 
<< end_version()
+              << ", state from ROWSET_UNLOADED to ROWSET_LOADED. tabletid:"
+              << _rowset_meta->tablet_id();
+    return OLAP_SUCCESS;
 }
 
 void Rowset::make_visible(Version version, VersionHash version_hash) {
diff --git a/be/src/olap/rowset/rowset.h b/be/src/olap/rowset/rowset.h
index d07c15e..7f0a0ca 100644
--- a/be/src/olap/rowset/rowset.h
+++ b/be/src/olap/rowset/rowset.h
@@ -20,11 +20,11 @@
 
 #include <memory>
 #include <vector>
+#include <mutex>
 
 #include "gen_cpp/olap_file.pb.h"
 #include "gutil/macros.h"
 #include "olap/rowset/rowset_meta.h"
-#include "util/once.h"
 
 namespace doris {
 
@@ -37,6 +37,61 @@ class RowsetFactory;
 class RowsetReader;
 class TabletSchema;
 
+// the rowset state transfer graph:
+//    ROWSET_UNLOADED    <--|
+//          ↓               |
+//    ROWSET_LOADED         |
+//          ↓               |
+//    ROWSET_UNLOADING   -->| 
+enum RowsetState {
+    // state for new created rowset
+    ROWSET_UNLOADED,
+    // state after load() called
+    ROWSET_LOADED,
+    // state for closed() called but owned by some readers
+    ROWSET_UNLOADING
+};
+
+class RowsetStateMachine {
+public:
+    RowsetStateMachine() : _rowset_state(ROWSET_UNLOADED) { }
+
+    OLAPStatus on_load() {
+        switch (_rowset_state) {
+            case ROWSET_UNLOADED:
+                _rowset_state = ROWSET_LOADED;
+                break;
+
+            default:
+                return OLAP_ERR_ROWSET_INVALID_STATE_TRANSITION;
+        }
+        return OLAP_SUCCESS;
+    }
+
+    OLAPStatus on_close(uint64_t refs_by_reader) {
+        switch (_rowset_state) {
+            case ROWSET_LOADED:
+                if (refs_by_reader == 0) {
+                    _rowset_state = ROWSET_UNLOADED;
+                } else {
+                    _rowset_state = ROWSET_UNLOADING;
+                }
+                break;
+
+            default:
+                return OLAP_ERR_ROWSET_INVALID_STATE_TRANSITION;
+        }
+        return OLAP_SUCCESS;
+    }
+
+    RowsetState rowset_state() {
+        return _rowset_state;
+    }
+
+private:
+    RowsetState _rowset_state;
+};
+
 class Rowset : public std::enable_shared_from_this<Rowset> {
 public:
     virtual ~Rowset() { }
@@ -95,6 +150,37 @@ public:
     // TODO should we rename the method to remove_files() to be more specific?
     virtual OLAPStatus remove() = 0;
 
+    // close to clear the resource owned by rowset
+    // including: open files, indexes and so on
+    // NOTICE: can not call this function in multithreads
+    void close() {
+        RowsetState old_state = _rowset_state_machine.rowset_state();
+        if (old_state != ROWSET_LOADED) {
+            return;
+        }
+        OLAPStatus st = OLAP_SUCCESS;
+        {
+            std::lock_guard<std::mutex> close_lock(_lock);
+            uint64_t current_refs = _refs_by_reader;
+            old_state = _rowset_state_machine.rowset_state();
+            if (old_state != ROWSET_LOADED) {
+                return;
+            }
+            if (current_refs == 0) {
+                do_close();
+            }
+            st = _rowset_state_machine.on_close(current_refs);
+        }
+        if (st != OLAP_SUCCESS) {
+            LOG(WARNING) << "state transition failed from:" << 
_rowset_state_machine.rowset_state();
+            return;
+        }
+        LOG(INFO) << "rowset is close. rowset state from:" << old_state
+                  << " to " << _rowset_state_machine.rowset_state()
+                  << ", version:" << start_version() << "-" << end_version()
+                  << ", tabletid:" << _rowset_meta->tablet_id();
+    }
+
     // hard link all files in this rowset to `dir` to form a new rowset with 
id `new_rowset_id`.
     virtual OLAPStatus link_files_to(const std::string& dir, RowsetId 
new_rowset_id) = 0;
 
@@ -127,6 +213,32 @@ public:
         return left->end_version() < right->end_version();
     }
 
+    // this function is called by reader to increase reference of rowset
+    void aquire() {
+        ++_refs_by_reader;
+    }
+
+    void release() {
+        // if the refs by reader is 0 and the rowset is closed, should release 
the resouce
+        uint64_t current_refs = --_refs_by_reader;
+        if (current_refs == 0 && _rowset_state_machine.rowset_state() == 
ROWSET_UNLOADING) {
+            {
+                std::lock_guard<std::mutex> release_lock(_lock);
+                // rejudge _refs_by_reader because we do not add lock in 
create reader
+                if (_refs_by_reader == 0 && 
_rowset_state_machine.rowset_state() == ROWSET_UNLOADING) {
+                    // first do close, then change state
+                    do_close();
+                    _rowset_state_machine.on_close(0);
+                }
+            }
+            if (_rowset_state_machine.rowset_state() == ROWSET_UNLOADED) {
+                LOG(INFO) << "close the rowset. rowset state from 
ROWSET_UNLOADING to ROWSET_UNLOADED"
+                          << ", version:" << start_version() << "-" << 
end_version()
+                          << ", tabletid:" << _rowset_meta->tablet_id();
+            }
+        }
+    }
+
 protected:
     friend class RowsetFactory;
 
@@ -140,7 +252,10 @@ protected:
     virtual OLAPStatus init() = 0;
 
     // The actual implementation of load(). Guaranteed by to called exactly 
once.
-    virtual OLAPStatus do_load_once(bool use_cache) = 0;
+    virtual OLAPStatus do_load(bool use_cache) = 0;
+
+    // release resources in this api
+    virtual void do_close() = 0;
 
     // allow subclass to add custom logic when rowset is being published
     virtual void make_visible_extra(Version version, VersionHash version_hash) 
{}
@@ -152,8 +267,13 @@ protected:
     bool _is_pending;    // rowset is pending iff it's not in visible state
     bool _is_cumulative; // rowset is cumulative iff it's visible and start 
version < end version
 
-    DorisCallOnce<OLAPStatus> _load_once;
+    // mutex lock for load/close api because it is costly
+    std::mutex _lock;
     bool _need_delete_file = false;
+    // variable to indicate how many rowset readers owned this rowset
+    std::atomic<uint64_t> _refs_by_reader;
+    // rowset state machine
+    RowsetStateMachine _rowset_state_machine;
 };
 
 } // namespace doris
diff --git a/be/src/olap/storage_engine.cpp b/be/src/olap/storage_engine.cpp
index 0bac06d..23e9dec 100644
--- a/be/src/olap/storage_engine.cpp
+++ b/be/src/olap/storage_engine.cpp
@@ -748,7 +748,7 @@ void StorageEngine::start_delete_unused_rowset() {
     for (auto it = _unused_rowsets.begin(); it != _unused_rowsets.end();) {
         if (it->second.use_count() != 1) {
             ++it;
-        } else if (it->second->need_delete_file()){
+        } else if (it->second->need_delete_file()) {
             LOG(INFO) << "start to remove rowset:" << it->second->rowset_id()
                     << ", version:" << it->second->version().first << "-" << 
it->second->version().second;
             OLAPStatus status = it->second->remove();
@@ -769,6 +769,7 @@ void StorageEngine::add_unused_rowset(RowsetSharedPtr 
rowset) {
     auto it = _unused_rowsets.find(rowset->unique_id());
     if (it == _unused_rowsets.end()) {
         rowset->set_need_delete_file();
+        rowset->close();
         _unused_rowsets[rowset->unique_id()] = rowset;
         release_rowset_id(rowset->rowset_id());
     }


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to