diff --git a/src/sdk/namespace_fs.js b/src/sdk/namespace_fs.js index 11dd19a41e..1fcf889332 100644 --- a/src/sdk/namespace_fs.js +++ b/src/sdk/namespace_fs.js @@ -1356,12 +1356,7 @@ class NamespaceFS { await this._assign_dir_content_to_xattr(fs_context, fs_xattr, params, copy_xattr); // when .folder exist and it's no upload flow - .folder should be deleted if it exists - try { - await nb_native().fs.unlink(fs_context, file_path); - } catch (err) { - if (err.code !== 'ENOENT') throw err; - dbg.log0(`namespace_fs._create_empty_dir_content: dir object file ${config.NSFS_FOLDER_OBJECT_NAME} was already deleted`); - } + await native_fs_utils.unlink_ignore_enoent(fs_context, file_path); const dir_path = this._get_file_md_path(params); const stat = await nb_native().fs.stat(fs_context, dir_path); const upload_info = this._get_upload_info(stat, fs_xattr[XATTR_VERSION_ID]); @@ -1916,11 +1911,7 @@ class NamespaceFS { async _delete_single_object(fs_context, file_path, params) { - try { - await nb_native().fs.unlink(fs_context, file_path); - } catch (err) { - if (err.code !== 'ENOENT') throw err; - } + await native_fs_utils.unlink_ignore_enoent(fs_context, file_path); await this._delete_path_dirs(file_path, fs_context); // when deleting the data of a directory object, we need to remove the directory dir object xattr // if the dir still exists - occurs when deleting dir while the dir still has entries in it @@ -2777,7 +2768,7 @@ class NamespaceFS { await native_fs_utils.safe_unlink(fs_context, file_path, version_info, gpfs_options, bucket_tmp_dir_path); return { ...version_info, latest: true }; } else { - await nb_native().fs.unlink(fs_context, file_path); + await native_fs_utils.unlink_ignore_enoent(fs_context, file_path); } return version_info; } catch (err) { diff --git a/src/test/unit_tests/jest_tests/test_versioning_concurrency.test.js b/src/test/unit_tests/jest_tests/test_versioning_concurrency.test.js index faa98e4c8b..022ab00ea9 100644 --- a/src/test/unit_tests/jest_tests/test_versioning_concurrency.test.js +++ b/src/test/unit_tests/jest_tests/test_versioning_concurrency.test.js @@ -59,4 +59,26 @@ describe('test versioning concurrency', () => { const versions = await nsfs.list_object_versions({ bucket: bucket }, DUMMY_OBJECT_SDK); expect(versions.objects.length).toBe(5); }); + + it('multiple delete version id and key', async () => { + const bucket = 'bucket1'; + const key = 'key2'; + const versions_arr = []; + // upload 5 versions of key2 + for (let i = 0; i < 5; i++) { + const random_data = Buffer.from(String(i)); + const body = buffer_utils.buffer_to_read_stream(random_data); + const res = await nsfs.upload_object({ bucket: bucket, key: key, source_stream: body }, DUMMY_OBJECT_SDK).catch(err => console.log('put error - ', err)); + versions_arr.push(res.etag); + } + const mid_version_id = versions_arr[3]; + const number_of_successful_operations = []; + for (let i = 0; i < 15; i++) { + nsfs.delete_object({ bucket: bucket, key: key, version_id: mid_version_id }, DUMMY_OBJECT_SDK) + .then(res => number_of_successful_operations.push(res)) + .catch(err => console.log('delete the same key & version id error - ', err)); + } + await P.delay(1000); + expect(number_of_successful_operations.length).toBe(15); + }); }); diff --git a/src/util/native_fs_utils.js b/src/util/native_fs_utils.js index ec9695678e..547c72657f 100644 --- a/src/util/native_fs_utils.js +++ b/src/util/native_fs_utils.js @@ -229,6 +229,23 @@ async function safe_unlink_posix(fs_context, to_delete_path, to_delete_version_i } } +/** + * unlink_ignore_enoent unlinks a file and if recieved an ENOENT error it'll not fail + * @param {nb.NativeFSContext} fs_context + * @param {String} to_delete_path + * @returns {Promise} + */ +async function unlink_ignore_enoent(fs_context, to_delete_path) { + dbg.log1('native_fs_utils.unlink_ignore_enoent:', to_delete_path); + try { + await nb_native().fs.unlink(fs_context, to_delete_path); + } catch (err) { + dbg.warn(`native_fs_utils.unlink_ignore_enoent unlink error: file path ${to_delete_path} error`, err); + if (err.code !== 'ENOENT') throw err; + dbg.warn(`native_fs_utils.unlink_ignore_enoent unlink: file ${to_delete_path} already deleted, ignoring..`); + } +} + // safe_link_gpfs links source_path to dest_path while verifing dest.fd async function safe_link_gpfs(fs_context, dst_path, src_file, dst_file) { dbg.log1('Namespace_fs.safe_link_gpfs source_file:', src_file, src_file.fd, dst_file, dst_file && dst_file.fd); @@ -671,6 +688,7 @@ exports.validate_bucket_creation = validate_bucket_creation; exports.is_path_exists = is_path_exists; exports.is_dir_rw_accessible = is_dir_rw_accessible; exports.folder_delete = folder_delete; +exports.unlink_ignore_enoent = unlink_ignore_enoent; exports.get_bucket_tmpdir_full_path = get_bucket_tmpdir_full_path; exports.get_bucket_tmpdir_name = get_bucket_tmpdir_name; exports.entity_enum = entity_enum;