Skip to content

Commit

Permalink
[73] Implement preserve replication functionality
Browse files Browse the repository at this point in the history
Add test for modify time preservation
  • Loading branch information
JustinKyleJames committed May 10, 2024
1 parent 59cd4d4 commit 147be2f
Show file tree
Hide file tree
Showing 2 changed files with 69 additions and 0 deletions.
30 changes: 30 additions & 0 deletions DSI/globus_gridftp_server_iRODS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ extern "C" {
#include <irods/thread_pool.hpp>
#include <irods/filesystem.hpp>
#include <irods/base64.hpp>
#include <irods/touch.h>

// boost includes
#include <boost/algorithm/string.hpp>
Expand Down Expand Up @@ -212,6 +213,7 @@ int convert_base64_to_hex_string(const std::string& base64_str, const int& bit_c
return 0;
}

// removes all trailing slashes and replaces consecutive slashes with a single slash
int
iRODS_l_reduce_path(
char * path)
Expand Down Expand Up @@ -282,6 +284,9 @@ struct globus_l_gfs_iRODS_handle_t
uint64_t irods_parallel_file_size_threshold_bytes;

bool first_write_done;

// added to get file modification time from client
time_t utime;
};

std::condition_variable outstanding_cntr_cv;
Expand Down Expand Up @@ -2041,6 +2046,18 @@ globus_l_gfs_iRODS_recv(
}
}

result = globus_gridftp_server_get_recv_modification_time(op, &iRODS_handle->utime);
if(result != GLOBUS_SUCCESS)
{
// continue but don't modify utime
globus_gfs_log_message(GLOBUS_GFS_LOG_ERR,"iRODS: globus_gridftp_server_get_recv_modification_time error.\n");
iRODS_handle->utime = -1;
}
else
{
globus_gfs_log_message(GLOBUS_GFS_LOG_INFO,"iRODS: globus_gridftp_server_get_recv_modification_time returned %lld.\n", static_cast<long long>(iRODS_handle->utime));
}

// the main thread is the first writer so thread_pool starts number_of_irods_write_threads-1 threads
irods::thread_pool threads{number_of_irods_write_threads-1};

Expand Down Expand Up @@ -2180,6 +2197,19 @@ globus_l_gfs_iRODS_recv(
memset (&dataObjCloseInp, 0, sizeof (dataObjCloseInp));
dataObjCloseInp.l1descInx = iRODS_handle->fd;
rcDataObjClose(iRODS_handle->conn, &dataObjCloseInp);

// update the modify time if preservation option selected
if (iRODS_handle->utime > 0)
{
nlohmann::json json_input;
json_input["logical_path"] = collection;
json_input["options"]["no_create"] = true;
json_input["options"]["seconds_since_epoch"] = iRODS_handle->utime;
if (const auto ec = rc_touch(iRODS_handle->conn, json_input.dump().c_str()); ec < 0) {
globus_gfs_log_message(GLOBUS_GFS_LOG_ERR,
"iRODS: Caught error (%d) trying to update the modify time for [%s]. Continuing without updating modify time.\n", ec, collection);
}
}

free(collection);
collection = nullptr;
Expand Down
39 changes: 39 additions & 0 deletions tests/globus_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,6 +215,45 @@ def test_file_rename_with_ftp(self):
ftp.login(user='user1', passwd='pass')
ftp.delete(f'/tempZone/home/user1/{filename2}')

def test_preserve_file_modification_time(self):
filename = f'{inspect.currentframe().f_code.co_name}1'
modify_time = '19710827010000'

try:
make_arbitrary_file(filename, 100*1024)
with FTP() as ftp:
ftp.connect(host='localhost', port=2811)
ftp.login(user='user1', passwd='pass')

# tell the server to send a hardcoded file modification time
ftp.sendcmd(f'site storattr modify={modify_time};')

# write the file that will be renamed
with open(filename,'rb') as f:
ftp.storbinary(f'STOR /tempZone/home/user1/{filename}', f)

# check the file modification time
with FTP() as ftp:
ftp.connect(host='localhost', port=2811)
ftp.login(user='user1', passwd='pass')

rv = ftp.mlsd(f'/tempZone/home/user1/{filename}', facts=['modify'])

# mlsd returns a generator object yielding a tuple of two elements for every file found in path.
# First element is the file name, the second one is a dictionary containing facts about the file name.
entry = next(rv)
self.assertEqual(f'/tempZone/home/user1/{filename}', entry[0])
self.assertEqual(modify_time, entry[1]['modify'])

finally:
os.remove(filename)

# remove file via ftp
with FTP() as ftp:
ftp.connect(host='localhost', port=2811)
ftp.login(user='user1', passwd='pass')
ftp.delete(f'/tempZone/home/user1/{filename}')

def test_directory_creation_renaming_removal_with_ftp(self):
filename = f'{inspect.currentframe().f_code.co_name}1'

Expand Down

0 comments on commit 147be2f

Please sign in to comment.