|
46 | 46 | #include "util/dynamic_util.h" |
47 | 47 | #include "util/md5.h" |
48 | 48 | #include "util/string_util.h" |
| 49 | +#include "udf/python/python_server.h" |
49 | 50 |
|
50 | 51 | namespace doris { |
51 | 52 |
|
@@ -111,7 +112,15 @@ 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 | + } else { |
| 122 | + unlink(lib_file.c_str()); |
| 123 | + } |
115 | 124 | } |
116 | 125 | } |
117 | 126 |
|
@@ -174,10 +183,20 @@ Status UserFunctionCache::_load_entry_from_lib(const std::string& dir, const std |
174 | 183 | << ", other_checksum info: = " << it->second->debug_string(); |
175 | 184 | return Status::InternalError("duplicate function id"); |
176 | 185 | } |
| 186 | + |
| 187 | + std::string full_path = dir + "/" + file; |
177 | 188 | // 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); |
| 189 | + std::shared_ptr<UserFunctionCacheEntry> entry = |
| 190 | + UserFunctionCacheEntry::create_shared(function_id, checksum, full_path, lib_type); |
180 | 191 | entry->is_downloaded = true; |
| 192 | + |
| 193 | + // For Python UDF, _check_cache_is_python_udf has already unzipped the file. |
| 194 | + // Set lib_file to the unzipped directory. |
| 195 | + if (lib_type == LibType::PY_ZIP) { |
| 196 | + entry->lib_file = full_path.substr(0, full_path.size() - 4); |
| 197 | + entry->is_unziped = true; |
| 198 | + } |
| 199 | + |
181 | 200 | _entry_map[function_id] = entry; |
182 | 201 |
|
183 | 202 | return Status::OK(); |
@@ -547,4 +566,29 @@ Status UserFunctionCache::_check_and_return_default_java_udf_url(const std::stri |
547 | 566 | return Status::OK(); |
548 | 567 | } |
549 | 568 |
|
| 569 | +void UserFunctionCache::drop_function_cache(int64_t fid) { |
| 570 | + std::shared_ptr<UserFunctionCacheEntry> entry = nullptr; |
| 571 | + { |
| 572 | + std::lock_guard<std::mutex> l(_cache_lock); |
| 573 | + auto it = _entry_map.find(fid); |
| 574 | + if (it == _entry_map.end()) { |
| 575 | + return; |
| 576 | + } |
| 577 | + entry = it->second; |
| 578 | + _entry_map.erase(it); |
| 579 | + } |
| 580 | + |
| 581 | + // For Python UDF, clear module cache in Python server before deleting files |
| 582 | + if (entry->type == LibType::PY_ZIP && !entry->lib_file.empty()) { |
| 583 | + auto status = PythonServerManager::instance().clear_module_cache(entry->lib_file); |
| 584 | + if (!status.ok()) [[unlikely]] { |
| 585 | + LOG(WARNING) << "drop_function_cache: failed to clear Python module cache for " |
| 586 | + << entry->lib_file << ": " << status.to_string(); |
| 587 | + } |
| 588 | + } |
| 589 | + |
| 590 | + // Mark for deletion, destructor will delete the files |
| 591 | + entry->should_delete_library.store(true); |
| 592 | +} |
| 593 | + |
550 | 594 | } // namespace doris |
0 commit comments