Skip to content

Commit

Permalink
Added option to print rsync performance stats in cf-net
Browse files Browse the repository at this point in the history
The performance stats are also logged. This way we can also study the
performance through `cf-agent`'s debug logs.

The following is an example of running cf-net with the `--stats` option:

```
$ sudo /var/cfengine/bin/cf-net --stats --host 192.168.56.10 get /var/cfengine/masterfiles/promises.cf
Send signature statistics:
  16970 bytes in (read from 'promises.cf')
  2424 bytes out (sent to server)
Receive delta statistics:
  9 bytes in (received from server)
  16970 bytes out (written to 'promises.cf.cfnew')
```

Changelog: Title
Signed-off-by: Lars Erik Wik <[email protected]>
  • Loading branch information
larsewi committed Jan 23, 2025
1 parent 9c7dc43 commit 83c7c0f
Show file tree
Hide file tree
Showing 6 changed files with 77 additions and 15 deletions.
15 changes: 13 additions & 2 deletions cf-net/cf-net.c
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@ typedef struct
char *min_tls_version;
char *allow_ciphers;
char *use_protocol_version;
bool print_stats;
} CFNetOptions;

//*******************************************************************
Expand Down Expand Up @@ -114,6 +115,7 @@ static const struct option OPTIONS[] =
{"tls-version", required_argument, 0, 't'},
{"ciphers", required_argument, 0, 'c'},
{"protocol", required_argument, 0, 'p'},
{"stats", no_argument, 0, 's'},
{NULL, 0, 0, '\0'}
};

Expand All @@ -129,6 +131,7 @@ static const char *const HINTS[] =
"Minimum TLS version to use",
"TLS ciphers to use (comma-separated list)",
"Specify CFEngine protocol to use. Possible values: 'classic', 'tls', 'cookie', 'filestream', 'latest' (default)",
"Print rsync performance statistics to stderr",
NULL
};

Expand Down Expand Up @@ -234,6 +237,7 @@ static void CFNetSetDefault(CFNetOptions *opts){
opts->min_tls_version = NULL;
opts->allow_ciphers = NULL;
opts->use_protocol_version = NULL;
opts->print_stats = false;
}

static void CFNetOptionsClear(CFNetOptions *opts)
Expand Down Expand Up @@ -289,7 +293,7 @@ static int CFNetParse(int argc, char **argv,
*hostnames = NULL;
int c = 0;
int start_index = 1;
const char *optstr = "+hMg:H:p:dvI"; // + means stop for non opt arg. :)
const char *optstr = "+hMg:H:p:sdvI"; // + means stop for non opt arg. :)
while ((c = getopt_long(argc, argv, optstr, OPTIONS, &start_index))
!= -1)
{
Expand Down Expand Up @@ -361,6 +365,11 @@ static int CFNetParse(int argc, char **argv,
opts->use_protocol_version = xstrdup(optarg);
break;
}
case 's':
{
opts->print_stats = true;
break;
}
default:
{
// printf("Default optarg = '%s', c = '%c' = %i\n",
Expand Down Expand Up @@ -725,6 +734,7 @@ static int invalid_command(const char *cmd)
typedef struct _GetFileData {
const char *hostname;
const char *use_protocol_version;
bool print_stats;
char remote_file[PATH_MAX];
char local_file[PATH_MAX];
bool ret;
Expand All @@ -741,7 +751,7 @@ static void *CFNetGetFile(void *arg)
}

data->ret = ProtocolStatGet(conn, data->remote_file,
data->local_file, 0644);
data->local_file, 0644, data->print_stats);
if (!data->ret)
{
printf("Could not stat: '%s'\n", data->remote_file);
Expand Down Expand Up @@ -858,6 +868,7 @@ static int CFNetGet(ARG_UNUSED CFNetOptions *opts, const char *hostname, char **
threads[i]->data = (GetFileData*) xcalloc(1, sizeof(GetFileData));
threads[i]->data->hostname = hostname;
threads[i]->data->use_protocol_version = opts->use_protocol_version;
threads[i]->data->print_stats = opts->print_stats;
if (n_threads > 1)
{
if (strstr(local_file, "%d") != NULL)
Expand Down
2 changes: 1 addition & 1 deletion libcfnet/client_code.c
Original file line number Diff line number Diff line change
Expand Up @@ -796,7 +796,7 @@ bool CopyRegularFileNet(const char *source, const char *basis, const char *dest,

const ProtocolVersion version = ConnectionInfoProtocolVersion(conn->conn_info);
if (ProtocolSupportsFileStream(version)) {
return FileStreamFetch(conn->conn_info->ssl, basis, dest, mode);
return FileStreamFetch(conn->conn_info->ssl, basis, dest, mode, false);
}

int dd = safe_open_create_perms(dest, O_WRONLY | O_CREAT | O_TRUNC | O_EXCL | O_BINARY, mode);
Expand Down
52 changes: 47 additions & 5 deletions libcfnet/file_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -672,13 +672,18 @@ static rs_long_t GetSizeOfFile(FILE *file)
*
* @param conn The SSL connection object
* @param filename The name of the basis file
* @param print_stats Whether or not to print performance statistics
* @return true on success, otherwise false
*/
static bool SendSignature(SSL *conn, const char *filename)
static bool SendSignature(SSL *conn, const char *filename, bool print_stats)
{
assert(conn != NULL);
assert(filename != NULL);

/* Variables used for performance statistics */
size_t bytes_in = 0;
size_t bytes_out = 0;

/* In this case, the input buffer does not need to be twice the message
* size, because we can control how much we read into it */
char in_buf[PROTOCOL_MESSAGE_SIZE], out_buf[PROTOCOL_MESSAGE_SIZE];
Expand Down Expand Up @@ -783,6 +788,7 @@ static bool SendSignature(SSL *conn, const char *filename)

bufs.next_in = in_buf;
bufs.avail_in += n_bytes;
bytes_in += n_bytes;
}

/* Iterate job */
Expand Down Expand Up @@ -813,6 +819,7 @@ static bool SendSignature(SSL *conn, const char *filename)

bufs.next_out = out_buf;
bufs.avail_out = PROTOCOL_MESSAGE_SIZE;
bytes_out += present;
}
else if (res == RS_DONE)
{
Expand All @@ -829,6 +836,16 @@ static bool SendSignature(SSL *conn, const char *filename)
fclose(file);
rs_job_free(job);

const char *msg =
"Send signature statistics:\n"
" %zu bytes in (read from '%s')\n"
" %zu bytes out (sent to server)\n";
Log(LOG_LEVEL_DEBUG, msg, bytes_in, filename, bytes_out);
if (print_stats)
{
fprintf(stderr, msg, bytes_in, filename, bytes_out);
}

return true;
}

Expand All @@ -839,15 +856,24 @@ static bool SendSignature(SSL *conn, const char *filename)
* @param basis The name of basis file
* @param dest The name of destination file
* @param perms The desired file permissions of the destination file
* @param print_stats Whether or not to print performance statistics
* @return true on success, otherwise false
*/
static bool RecvDelta(
SSL *conn, const char *basis, const char *dest, mode_t perms)
SSL *conn,
const char *basis,
const char *dest,
mode_t perms,
bool print_stats)
{
assert(conn != NULL);
assert(basis != NULL);
assert(dest != NULL);

/* Variables used for performance statistics */
size_t bytes_in = 0;
size_t bytes_out = 0;

/* The input buffer has to be twice the message size, so that it can fit a
* new message, as well as some tail data from the last job iteration */
char in_buf[PROTOCOL_MESSAGE_SIZE * 2], out_buf[PROTOCOL_MESSAGE_SIZE];
Expand Down Expand Up @@ -953,6 +979,7 @@ static bool RecvDelta(
bufs.eof_in = eof ? 1 : 0;
bufs.next_in = in_buf;
bufs.avail_in += n_bytes;
bytes_in += n_bytes;
}

res = rs_job_iter(job, &bufs);
Expand Down Expand Up @@ -998,6 +1025,7 @@ static bool RecvDelta(
n_wrote_total += present;
bufs.next_out = out_buf;
bufs.avail_out = sizeof(out_buf);
bytes_out += present;
}
} while (res != RS_DONE);

Expand All @@ -1012,11 +1040,25 @@ static bool RecvDelta(
return false;
}

const char *msg =
"Receive delta statistics:\n"
" %zu bytes in (received from server)\n"
" %zu bytes out (written to '%s')\n";
Log(LOG_LEVEL_DEBUG, msg, bytes_in, bytes_out, dest);
if (print_stats)
{
fprintf(stderr, msg, bytes_in, bytes_out, dest);
}

return true;
}

bool FileStreamFetch(
SSL *conn, const char *basis, const char *dest, mode_t perms)
SSL *conn,
const char *basis,
const char *dest,
mode_t perms,
bool print_stats)
{
assert(conn != NULL);
assert(basis != NULL);
Expand All @@ -1032,7 +1074,7 @@ bool FileStreamFetch(
Log(LOG_LEVEL_VERBOSE,
"Computing- & sending signature of file '%s'...",
basis);
if (!SendSignature(conn, basis))
if (!SendSignature(conn, basis, print_stats))
{
/* Error is already logged */
return false;
Expand All @@ -1041,7 +1083,7 @@ bool FileStreamFetch(
Log(LOG_LEVEL_VERBOSE,
"Receiving delta & applying patch to file '%s'...",
dest);
if (!RecvDelta(conn, basis, dest, perms))
if (!RecvDelta(conn, basis, dest, perms, print_stats))
{
/* Error is already logged */
return false;
Expand Down
7 changes: 6 additions & 1 deletion libcfnet/file_stream.h
Original file line number Diff line number Diff line change
Expand Up @@ -93,12 +93,17 @@ bool FileStreamServe(SSL *conn, const char *filename);
* @param basis The name of the basis file
* @param dest The name of the destination file
* @param perms The desired permissions of the destination file
* @param print_stats Print performance statistics
* @return true on success, otherwise false
*
* @note If the destination file is a symlink, this function fetches the
* contents into the symlink target.
*/
bool FileStreamFetch(
SSL *conn, const char *basis, const char *dest, mode_t perms);
SSL *conn,
const char *basis,
const char *dest,
mode_t perms,
bool print_stats);

#endif // FILE_STREAM_H
10 changes: 6 additions & 4 deletions libcfnet/protocol.c
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,8 @@ Seq *ProtocolOpenDir(AgentConnection *conn, const char *path)
}

bool ProtocolGet(AgentConnection *conn, const char *remote_path,
const char *local_path, const uint32_t file_size, int perms)
const char *local_path, const uint32_t file_size, int perms,
bool print_stats)
{
assert(conn != NULL);
assert(remote_path != NULL);
Expand Down Expand Up @@ -128,7 +129,8 @@ bool ProtocolGet(AgentConnection *conn, const char *remote_path,
if (ProtocolSupportsFileStream(version))
{
/* Use file stream API if it is available */
if (!FileStreamFetch(conn->conn_info->ssl, local_path, dest, perms))
if (!FileStreamFetch(conn->conn_info->ssl, local_path, dest, perms,
print_stats))
{
/* Error is already logged */
success = false;
Expand Down Expand Up @@ -222,7 +224,7 @@ bool ProtocolGet(AgentConnection *conn, const char *remote_path,
}

bool ProtocolStatGet(AgentConnection *conn, const char *remote_path,
const char *local_path, int perms)
const char *local_path, int perms, bool print_stats)
{
assert(conn != NULL);
assert(remote_path != NULL);
Expand All @@ -237,7 +239,7 @@ bool ProtocolStatGet(AgentConnection *conn, const char *remote_path,
return false;
}

return ProtocolGet(conn, remote_path, local_path, sb.st_size, perms);
return ProtocolGet(conn, remote_path, local_path, sb.st_size, perms, print_stats);
}

bool ProtocolStat(AgentConnection *const conn, const char *const remote_path,
Expand Down
6 changes: 4 additions & 2 deletions libcfnet/protocol.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,6 +84,7 @@ Seq *ProtocolOpenDir(AgentConnection *conn, const char *path);
* @param [in] local_path Path of received file
* @param [in] file_size Size of file to get
* @param [in] perms Permissions of local file
* @param [in] print_stats Print RSYNC performance statistics
* @return True if file was successfully transferred, false otherwise
*
* Example (for printing each directory entry):
Expand All @@ -104,7 +105,8 @@ Seq *ProtocolOpenDir(AgentConnection *conn, const char *path);
* Translated to: GET /var/cfengine/masterfiles/update.cf
*/
bool ProtocolGet(AgentConnection *conn, const char *remote_path,
const char *local_path, const uint32_t file_size, int perms);
const char *local_path, const uint32_t file_size, int perms,
bool print_stats);


/**
Expand All @@ -114,7 +116,7 @@ bool ProtocolGet(AgentConnection *conn, const char *remote_path,
* it.
*/
bool ProtocolStatGet(AgentConnection *conn, const char *remote_path,
const char *local_path, int perms);
const char *local_path, int perms, bool print_stats);

/**
* Receives statistics about a remote file.
Expand Down

0 comments on commit 83c7c0f

Please sign in to comment.