|
42 | 42 | #include "io/fs/local_file_system.h" |
43 | 43 | #include "runtime/exec_env.h" |
44 | 44 | #include "runtime/plugin/cloud_plugin_downloader.h" |
| 45 | +#include "udf/python/python_server.h" |
45 | 46 | #include "util/defer_op.h" |
46 | 47 | #include "util/dynamic_util.h" |
47 | 48 | #include "util/md5.h" |
@@ -111,7 +112,20 @@ UserFunctionCacheEntry::~UserFunctionCacheEntry() { |
111 | 112 |
|
112 | 113 | // delete library file if should_delete_library is set |
113 | 114 | if (should_delete_library.load()) { |
114 | | - unlink(lib_file.c_str()); |
| 115 | + if (type == LibType::PY_ZIP) { |
| 116 | + // For Python UDF, we need to delete both the unzipped directory and the original zip file. |
| 117 | + auto st = io::global_local_filesystem()->delete_directory_or_file(lib_file); |
| 118 | + |
| 119 | + st = io::global_local_filesystem()->delete_file(lib_file + ".zip"); |
| 120 | + |
| 121 | + if (!st.ok()) [[unlikely]] { |
| 122 | + LOG(WARNING) << "failed to delete python udf files, lib_file=" << lib_file << ": " |
| 123 | + << st.to_string(); |
| 124 | + } |
| 125 | + |
| 126 | + } else { |
| 127 | + unlink(lib_file.c_str()); |
| 128 | + } |
115 | 129 | } |
116 | 130 | } |
117 | 131 |
|
@@ -174,10 +188,20 @@ Status UserFunctionCache::_load_entry_from_lib(const std::string& dir, const std |
174 | 188 | << ", other_checksum info: = " << it->second->debug_string(); |
175 | 189 | return Status::InternalError("duplicate function id"); |
176 | 190 | } |
| 191 | + |
| 192 | + std::string full_path = dir + "/" + file; |
177 | 193 | // create a cache entry and put it into entry map |
178 | | - std::shared_ptr<UserFunctionCacheEntry> entry = UserFunctionCacheEntry::create_shared( |
179 | | - function_id, checksum, dir + "/" + file, lib_type); |
| 194 | + std::shared_ptr<UserFunctionCacheEntry> entry = |
| 195 | + UserFunctionCacheEntry::create_shared(function_id, checksum, full_path, lib_type); |
180 | 196 | entry->is_downloaded = true; |
| 197 | + |
| 198 | + // For Python UDF, _check_cache_is_python_udf has already unzipped the file. |
| 199 | + // Set lib_file to the unzipped directory. |
| 200 | + if (lib_type == LibType::PY_ZIP) { |
| 201 | + entry->lib_file = full_path.substr(0, full_path.size() - 4); |
| 202 | + entry->is_unziped = true; |
| 203 | + } |
| 204 | + |
181 | 205 | _entry_map[function_id] = entry; |
182 | 206 |
|
183 | 207 | return Status::OK(); |
@@ -547,4 +571,29 @@ Status UserFunctionCache::_check_and_return_default_java_udf_url(const std::stri |
547 | 571 | return Status::OK(); |
548 | 572 | } |
549 | 573 |
|
| 574 | +void UserFunctionCache::drop_function_cache(int64_t fid) { |
| 575 | + std::shared_ptr<UserFunctionCacheEntry> entry = nullptr; |
| 576 | + { |
| 577 | + std::lock_guard<std::mutex> l(_cache_lock); |
| 578 | + auto it = _entry_map.find(fid); |
| 579 | + if (it == _entry_map.end()) { |
| 580 | + return; |
| 581 | + } |
| 582 | + entry = it->second; |
| 583 | + _entry_map.erase(it); |
| 584 | + } |
| 585 | + |
| 586 | + // For Python UDF, clear module cache in Python server before deleting files |
| 587 | + if (entry->type == LibType::PY_ZIP && !entry->lib_file.empty()) { |
| 588 | + auto status = PythonServerManager::instance().clear_module_cache(entry->lib_file); |
| 589 | + if (!status.ok()) [[unlikely]] { |
| 590 | + LOG(WARNING) << "drop_function_cache: failed to clear Python module cache for " |
| 591 | + << entry->lib_file << ": " << status.to_string(); |
| 592 | + } |
| 593 | + } |
| 594 | + |
| 595 | + // Mark for deletion, destructor will delete the files |
| 596 | + entry->should_delete_library.store(true); |
| 597 | +} |
| 598 | + |
550 | 599 | } // namespace doris |
0 commit comments