}
} //d4n_write_cache_enabled = true
+ /* Cache requests are indicated with the x-rgw-cache-request custom header during S3 ops so users can interact
+ * only with the cache. If the object is found in the cache, the request succeeds. If it is only in the backend,
+ * the request returns -ENOENT. */
+ if (cache_request) {
+ results = std::move(cache_results);
+ return 0;
+ }
+
//Get objects from backend store
auto ret = next->list(dpp, params, max, store_results, y);
if (ret < 0) {
bool follow_olh)
{
if (load_from_store) {
+ if (cache_request) {
+ return -ENOENT;
+ }
return next->load_obj_state(dpp, y, follow_olh);
}
bool has_instance = false;
}
return 0;
}
+ if (cache_request) {
+ return -ENOENT;
+ }
return next->load_obj_state(dpp, y, follow_olh);
}
}
if (!found_in_cache) {
+ if (cache_request) {
+ return -ENOENT;
+ }
auto ret = next->set_obj_attrs(dpp, setattrs, delattrs, y, flags);
if (ret < 0) {
ldpp_dout(dpp, 0) << "D4NFilterObject::" << __func__ << "(): set_obj_attrs method of backend store failed with ret: " << ret << dendl;
return 0;
}
+int D4NFilterObject::delete_cache_entry(const DoutPrefixProvider* dpp, const std::string key, optional_yield y) {
+ int ret;
+ if ((ret = driver->get_cache_driver()->delete_data(dpp, key, y)) == 0) { // Inline cache delete
+ if (!(ret = driver->get_policy_driver()->get_cache_policy()->erase(dpp, key, y))) {
+ ldpp_dout(dpp, 10) << "Failed to delete policy entry for: " << key << ", ret=" << ret << dendl;
+ return ret;
+ }
+ } else {
+ ldpp_dout(dpp, 10) << "Failed to delete object in cache for: " << key << ", ret=" << ret << dendl;
+ return ret;
+ }
+
+ return 0;
+}
+
int D4NFilterObject::delete_data_block_cache_entries(const DoutPrefixProvider* dpp, optional_yield y, std::string& version, bool dirty)
{
//delete cache entries
std::string key = get_key_in_cache(get_cache_block_prefix(this, version), std::to_string(fst), std::to_string(cur_len));
int ret;
- if ((ret = driver->get_cache_driver()->delete_data(dpp, key, y)) == 0) {
- if (!(ret = driver->get_policy_driver()->get_cache_policy()->erase(dpp, key, y))) {
- ldpp_dout(dpp, 0) << "Failed to delete policy entry for: " << key << ", ret=" << ret << dendl;
- return ret;
- }
- } else {
- ldpp_dout(dpp, 0) << "Failed to delete cache entry for: " << key << ", ret=" << ret << dendl;
- return ret;
+ if ((ret = delete_cache_entry(dpp, key, y)) < 0) {
+ return ret;
}
fst += cur_len;
} while(fst < lst);
ldpp_dout(dpp, 10) << "D4NFilterObject::" << __func__ << "(): " << " object " << this->get_name() << " does not exist." << dendl;
return -ENOENT;
} else if (!ret) {
+ if (cache_request) {
+ return -ENOENT;
+ }
if(perfcounter) {
perfcounter->inc(l_rgw_d4n_cache_misses);
}
return ret;
}
} else {
+ if (cache_request) {
+ return -ENOENT;
+ }
+
if (block.deleteMarker) {
ldpp_dout(dpp, 10) << "D4NFilterObject::" << __func__ << "(): object " << this->get_name() << " does not exist." << dendl;
return -ENOENT;
}
}
if (!found_in_cache) {
+ if (cache_request) {
+ return -ENOENT;
+ }
if (auto ret = next->delete_obj_attrs(dpp, attr_name, y); ret < 0) {
ldpp_dout(dpp, 0) << "D4NFilterObject::" << __func__ << "(): delete_obj_attrs method of backend store failed with ret: " << ret << dendl;
return ret;
ldpp_dout(dpp, 10) << "D4NFilterObject::D4NFilterReadOp::" << __func__ << "(): object " << source->get_name() << " does not exist." << dendl;
return -ENOENT;
} else if (!ret) {
+ if (source->is_cache_request()) {
+ return -ENOENT;
+ }
if(perfcounter) {
perfcounter->inc(l_rgw_d4n_cache_misses);
}
adjusted_len -= max_chunk_size;
} while (start_part_num < num_parts);
}
+
+ if (source->cache_request) {
+ return -ENOENT;
+ }
+
ldpp_dout(dpp, 20) << "D4NFilterObject::iterate:: " << __func__ << "(): Fetching object from backend store" << dendl;
Attrs obj_attrs;
std::string head_oid_in_cache;
rgw::d4n::CacheBlock block;
int ret = -1;
+ bool cache_request = source->cache_request;
/* check_head_exists_in_cache_get_oid also returns false if the head object is in the cache, but is a delete marker.
As a result, the below check guarantees the head object is not in the cache. */
if (!source->check_head_exists_in_cache_get_oid(dpp, head_oid_in_cache, attrs, block, y) && !block.deleteMarker) {
/* for a dirty object, if the first call is a simple delete after versioning is enabled, the call will go to the backend store and create a delete marker there
since no object with source->get_name() will be found in the cache (and this is correct) */
+ if (cache_request) {
+ return -ENOENT;
+ }
ldpp_dout(dpp, 10) << "D4NFilterObject::" << __func__ << "(): head object not found; calling next->delete_obj" << dendl;
next->params = params;
ret = next->delete_obj(dpp, y, flags);
objName = "_" + source->get_name();
}
- if (objDirty) { // head object dirty flag represents object dirty flag
+ if (objDirty && !cache_request) { // head object dirty flag represents object dirty flag
//for versioned buckets, for a simple delete we need to create a delete marker (and not invalidate/delete any object)
if (!source->get_bucket()->versioned() || (block.cacheObj.objName != source->get_name())) {
ldpp_dout(dpp, 10) << "D4NFilterObject::" << __func__ << "(): calling invalidate_dirty_object for: " << head_oid_in_cache << dendl;
ldpp_dout(dpp, 0) << "Failed to delete head object in block directory for: " << block.cacheObj.objName << ", ret=" << ret << dendl;
return ret;
}
+ if (cache_request) {
+ if ((ret = source->delete_cache_entry(dpp, get_cache_block_prefix(source, version), y)) < 0) {
+ return ret;
+ }
+ }
}
/* if versioning is suspended, we might have a latest head entry created from when bucket was non-versioned
don't return error as that could already be deleted by set_head_obj_dir_entry */
if ((ret = blockDir->del(dpp, &block, y)) < 0) {
ldpp_dout(dpp, 0) << "Failed to delete head object in block directory for: " << block.cacheObj.objName << ", ret=" << ret << dendl;
}
+ if (cache_request) {
+ if ((ret = source->delete_cache_entry(dpp, head_oid_in_cache, y)) < 0) {
+ return ret;
+ }
+ }
}
} else if (objDirty) { //2. dirty objects - 1. add delete marker for simple request 2. delete version if given and correctly promote latest version if needed
bool transaction_success = false;
ldpp_dout(dpp, 0) << "D4NFilterObject::" << __func__ << "(): Failed to Queue zrem request in bucket directory for: " << source->get_name() << ", ret=" << ret << dendl;
return ret;
}
+ if (cache_request) {
+ std::string req_oid_in_cache = get_key_in_cache(head_oid_in_cache + "#0#0", std::to_string(0), std::to_string(0));
+ if ((ret = source->delete_cache_entry(dpp, req_oid_in_cache, y)) < 0) {
+ return ret;
+ }
+ }
}
} //end-if latest_block.version == block.version
//delete versioned entry (handles delete markers also)
ldpp_dout(dpp, 0) << "D4NFilterObject::" << __func__ << "(): Failed to execute exec in block directory: " << "ret= " << ret << dendl;
return ret;
}
+ if (cache_request) {
+ std::string req_oid_in_cache = get_key_in_cache(get_cache_block_prefix(source, version), std::to_string(0), std::to_string(0));
+ if ((ret = source->delete_cache_entry(dpp, req_oid_in_cache, y)) < 0) {
+ return ret;
+ }
+ }
result.delete_marker = block.deleteMarker;
result.version_id = version;
//success, hence break from loop
ldpp_dout(dpp, 0) << "D4NFilterObject::" << __func__ << "(): Failed to Queue delete head object op in block directory for: " << block.cacheObj.objName << ", ret=" << ret << dendl;
return ret;
}
+ if (cache_request) {
+ if ((ret = source->delete_cache_entry(dpp, head_oid_in_cache, y)) < 0) {
+ return ret;
+ }
+ }
//if we get request for latest head entry, delete the null block and vice versa
if (block.cacheObj.objName == objName) {
block.cacheObj.objName = "_:null_" + source->get_name();
return ret;
}
+ std::string req_oid_in_cache = get_key_in_cache(get_cache_block_prefix(source, version), std::to_string(block.blockID), std::to_string(block.size));
+ if (cache_request) {
+ if ((ret = source->delete_cache_entry(dpp, req_oid_in_cache, y)) < 0) {
+ return ret;
+ }
+ }
fst += cur_len;
} while (fst < lst);
}
if (!objDirty) {
+ if (cache_request) {
+ return 0;
+ }
next->params = params;
ldpp_dout(dpp, 10) << "D4NFilterObject::" << __func__ << "(): object is not dirty; calling next->delete_obj" << dendl;
ret = next->delete_obj(dpp, y, flags);
d4n_writecache = g_conf()->d4n_writecache_enabled;
if (!d4n_writecache) {
+ if (object->is_cache_request()) {
+ return -EINVAL;
+ }
ldpp_dout(dpp, 0) << "D4NFilterWriter::" << __func__ << "(): calling next->prepare" << dendl;
return next->prepare(y);
} else {
bufferlist bl = data;
off_t bl_len = bl.length();
off_t ofs = offset;
- bool dirty = true;
+ bool dirty;
std::string version = object->get_object_version();
std::string prefix = get_cache_block_prefix(obj, version);
int ret = 0;
if (!d4n_writecache) {
+ if (object->is_cache_request()) {
+ return -EINVAL;
+ }
ldpp_dout(dpp, 10) << "D4NFilterWriter::" << __func__ << "(): calling next process" << dendl;
return next->process(std::move(data), offset);
} else {
rgw::sal::Attrs attrs;
std::string oid = prefix + CACHE_DELIM + std::to_string(ofs);
std::string oid_in_cache = oid + CACHE_DELIM + std::to_string(bl_len);
- dirty = true;
+ if (!object->is_cache_request()) {
+ dirty = true;
+ }
ret = driver->get_policy_driver()->get_cache_policy()->eviction(dpp, bl.length(), y);
if (ret == 0) {
if (bl.length() > 0) {
ldpp_dout(dpp, 10) << "D4NFilterWriter::" << __func__ << "(): oid_in_cache is: " << oid_in_cache << dendl;
ret = driver->get_cache_driver()->put(dpp, oid_in_cache, bl, bl.length(), attrs, y);
if (ret == 0) {
- ret = driver->get_cache_driver()->set_attr(dpp, oid_in_cache, RGW_CACHE_ATTR_DIRTY, "1", y);
- if (ret == 0) {
- driver->get_policy_driver()->get_cache_policy()->update(dpp, oid_in_cache, ofs, bl.length(), version, dirty, rgw::d4n::RefCount::NOOP, y);
+ if (!object->is_cache_request()) {
+ dirty = true;
+ }
+ if (!object->is_cache_request()) {
+ ret = driver->get_cache_driver()->set_attr(dpp, oid_in_cache, RGW_CACHE_ATTR_DIRTY, "1", y);
+ if (ret == 0) {
+ driver->get_policy_driver()->get_cache_policy()->update(dpp, oid_in_cache, ofs, bl.length(), version, dirty, rgw::d4n::RefCount::NOOP, y);
+ }
+ } else {
+ driver->get_policy_driver()->get_cache_policy()->update(dpp, oid_in_cache, ofs, bl.length(), version, dirty, rgw::d4n::RefCount::NOOP, y);
}
} else {
ldpp_dout(dpp, 0) << "D4NFilterWriter::" << __func__ << "(): ERROR: writing data to the cache failed, ret=" << ret << dendl;
return ret;
}
- dirty = true;
+ if (!object->is_cache_request()) {
+ dirty = true;
+ }
ceph::real_time m_time;
if (mtime) {
if (real_clock::is_zero(*mtime)) {
object->set_attrs(attrs);
object->set_attrs_from_obj_state(dpp, y, attrs, dirty);
} else {
+ if (object->is_cache_request()) {
+ return -EINVAL;
+ }
// we need to call next->complete here so that we are able to correctly get the object state needed for caching head
ret = next->complete(accounted_size, etag, mtime, set_mtime, attrs, cksum,
delete_at, if_match, if_nomatch, user_data, zones_trace,