blob: 6112bcf19ced759ffad21bc73f94cf8af6a83fba [file]
/*
* 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.
*/
#pragma once
#include <glog/logging.h>
#include "velox/common/base/Exceptions.h"
#include <condition_variable>
#include <memory>
#include <mutex>
#include <queue>
namespace gluten {
template <typename T>
class CachedBatchQueue {
public:
explicit CachedBatchQueue(const int64_t capacity) : capacity_(capacity) {}
void put(std::shared_ptr<T> batch) {
std::unique_lock<std::mutex> lock(mtx_);
const auto batchSize = batch->numBytes();
VELOX_CHECK_LE(batchSize, capacity_, "Batch size exceeds queue capacity");
notFull_.wait(lock, [&]() { return noMoreBatches_ || totalSize_ + batchSize <= capacity_; });
if (noMoreBatches_) {
LOG(WARNING) << "Discard batch due to calling put() after noMoreBatches().";
return;
}
queue_.push(std::move(batch));
totalSize_ += batchSize;
notEmpty_.notify_one();
}
std::shared_ptr<T> get() {
std::unique_lock<std::mutex> lock(mtx_);
notEmpty_.wait(lock, [&]() { return noMoreBatches_ || !queue_.empty(); });
if (exception_) {
std::rethrow_exception(exception_);
}
if (queue_.empty()) {
return nullptr;
}
auto batch = std::move(queue_.front());
DLOG(INFO) << "CachedBatchQueue get(): Queue length=" << queue_.size() << ", queue size in bytes=" << totalSize_
<< ", current batch size in bytes=" << batch->numBytes();
queue_.pop();
totalSize_ -= batch->numBytes();
notFull_.notify_one();
return batch;
}
void noMoreBatches() {
std::lock_guard<std::mutex> lock(mtx_);
if (noMoreBatches_) {
return;
}
noMoreBatches_ = true;
notFull_.notify_all();
notEmpty_.notify_all();
}
/// Returns true if another producer has already set an exception.
/// Producers can poll this to abort early without waiting for put() to unblock.
bool hasException() const {
std::lock_guard<std::mutex> lock(mtx_);
return exception_ != nullptr;
}
/// Called by a producer thread to propagate an exception to the consumer.
/// Wakes up any blocked get() call, which will rethrow the exception.
void setException(std::exception_ptr e) {
std::lock_guard<std::mutex> lock(mtx_);
if (!exception_) {
exception_ = std::move(e);
}
noMoreBatches_ = true;
notFull_.notify_all();
notEmpty_.notify_all();
}
private:
int64_t size() const {
return totalSize_;
}
bool empty() const {
return queue_.empty();
}
int64_t capacity_;
int64_t totalSize_{0};
bool noMoreBatches_{false};
std::exception_ptr exception_{nullptr};
std::queue<std::shared_ptr<T>> queue_;
mutable std::mutex mtx_;
std::condition_variable notEmpty_;
std::condition_variable notFull_;
};
} // namespace gluten