| // Licensed to the Apache Software Foundation (ASF) under one | |
| // or more contributor license agreements. See the NOTICE file | |
| // distributed with this work for additional information | |
| // regarding copyright ownership. The ASF licenses this file | |
| // to you under the Apache License, Version 2.0 (the | |
| // "License"); you may not use this file except in compliance | |
| // with the License. You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, | |
| // software distributed under the License is distributed on an | |
| // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
| // KIND, either express or implied. See the License for the | |
| // specific language governing permissions and limitations | |
| // under the License. | |
| #include <stdint.h> | |
| #include <fstream> | |
| #include <iostream> | |
| #include <sstream> | |
| #include <string> | |
| #include "testutil/gtest-util.h" | |
| #include "common/init.h" | |
| #include "codegen/llvm-codegen.h" | |
| #include "runtime/test-env.h" | |
| #include "service/fe-support.h" | |
| #include "runtime/client-cache.h" | |
| #include "statestore/statestore-service-client-wrapper.h" | |
| using namespace std; | |
| namespace impala { | |
| class ClientCacheTest : public testing::Test { | |
| protected: | |
| // Pool for objects to be destroyed during test teardown. | |
| ObjectPool pool_; | |
| virtual void SetUp() {} | |
| virtual void TearDown() { pool_.Clear(); } | |
| void InitAddr(TNetworkAddress** addr) { | |
| *addr = pool_.Add(new TNetworkAddress()); | |
| (*addr)->__set_hostname("127.0.0.1"); | |
| (*addr)->__set_port(25000); | |
| } | |
| // Create a new client by the client cache. | |
| Status GetClient(shared_ptr<ClientCache<StatestoreServiceClientWrapper>>& cc, | |
| TNetworkAddress* addr, StatestoreServiceClientWrapper** ck) { | |
| return cc->GetClient(*addr, ck); | |
| } | |
| // Destroy the client. | |
| void DestroyClient(shared_ptr<ClientCache<StatestoreServiceClientWrapper>>& cc, | |
| StatestoreServiceClientWrapper** ck) { | |
| cc->DestroyClient(ck); | |
| } | |
| // Return the virtual memory size that the process is using. | |
| // Only works for Linux. | |
| uint64_t GetProcessVMSize() { | |
| // vm size, https://man7.org/linux/man-pages/man5/proc.5.html | |
| const int vm_size_pos = 22; | |
| ifstream stream("/proc/self/stat"); | |
| string line; | |
| string space_delimiter = " "; | |
| vector<string> words{}; | |
| if (getline(stream, line)) { | |
| size_t pos = 0; | |
| while ((pos = line.find(space_delimiter)) != string::npos) { | |
| words.push_back(line.substr(0, pos)); | |
| line.erase(0, pos + space_delimiter.length()); | |
| } | |
| } | |
| uint64_t value = 0; | |
| if (words.size() <= vm_size_pos) return value; | |
| istringstream iss(words[vm_size_pos]); | |
| iss >> value; | |
| return value; | |
| } | |
| }; | |
| // Testcase for IMPALA-11176 to verify the memory leak issue. | |
| // The memory is not supposed to increase after multiple rounds of client creation and | |
| // destruction. | |
| TEST_F(ClientCacheTest, MemLeak) { | |
| // IMPALA-11196 Testcase will fail in ASAN and TSAN build, therefore disabled. | |
| #if !defined(ADDRESS_SANITIZER) && !defined(THREAD_SANITIZER) | |
| int64_t create_num = 1000; | |
| TNetworkAddress* addr; | |
| InitAddr(&addr); | |
| uint64_t mem_before = GetProcessVMSize(); | |
| EXPECT_GT(mem_before, 0); | |
| // Create and destroy the client, the virtual memory usage of the process should not | |
| // increase. | |
| while (create_num-- > 0) { | |
| StatestoreServiceClientWrapper* ck = nullptr; | |
| shared_ptr<ClientCache<StatestoreServiceClientWrapper>> client_cache = | |
| std::make_shared<ClientCache<StatestoreServiceClientWrapper>>(); | |
| Status status = GetClient(client_cache, addr, &ck); | |
| EXPECT_TRUE(status.ok()); | |
| DestroyClient(client_cache, &ck); | |
| } | |
| uint64_t mem_after = GetProcessVMSize(); | |
| EXPECT_GE(mem_before, mem_after); | |
| #endif | |
| } | |
| } // namespace impala | |
| int main(int argc, char **argv) { | |
| ::testing::InitGoogleTest(&argc, argv); | |
| impala::InitCommonRuntime(argc, argv, true, impala::TestInfo::BE_TEST); | |
| impala::InitFeSupport(); | |
| ABORT_IF_ERROR(impala::LlvmCodeGen::InitializeLlvm()); | |
| return RUN_ALL_TESTS(); | |
| } |