Exemple #1
0
zdir_patch_t *
zdir_patch_new (const char *path, zfile_t *file,
                zdir_patch_op_t op, const char *alias)
{
    zdir_patch_t *self = (zdir_patch_t *) zmalloc (sizeof (zdir_patch_t));
    if (!self)
        return NULL;
    self->path = strdup (path);
    if (self->path)
        self->file = zfile_dup (file);
    if (!self->file) {
        zdir_patch_destroy (&self);
        return NULL;
    }

    self->op = op;

    //  Calculate virtual path for patch (remove path, prefix alias)
    char *filename = zfile_filename (file, path);
    if (!filename) {
        zdir_patch_destroy (&self);
        return NULL;
    }
    assert (*filename != '/');
    self->vpath = (char *) zmalloc (strlen (alias) + strlen (filename) + 2);
    if (alias [strlen (alias) - 1] == '/')
        sprintf (self->vpath, "%s%s", alias, filename);
    else
        sprintf (self->vpath, "%s/%s", alias, filename);
    return self;
}
Exemple #2
0
static void
sub_patch_add (sub_t *self, zdir_patch_t *patch)
{
    //  Skip file creation if client already has identical file
    zdir_patch_digest_set (patch);
    if (zdir_patch_op (patch) == patch_create) {
        char *digest = (char *) zhash_lookup (self->cache,
                                    zdir_patch_vpath (patch) + strlen(self->path) + 1);
        if (digest && streq (digest, zdir_patch_digest (patch)))
            return;             //  Just skip patch for this client
    }
    //  Remove any previous patches for the same file
    zdir_patch_t *existing = (zdir_patch_t *) zlist_first (self->client->patches);
    while (existing) {
        if (streq (zdir_patch_vpath (patch), zdir_patch_vpath (existing))) {
            zlist_remove (self->client->patches, existing);
            zdir_patch_destroy (&existing);
            break;
        }
        existing = (zdir_patch_t *) zlist_next (self->client->patches);
    }
    if (zdir_patch_op (patch) == patch_create)
        zhash_insert (self->cache,
            zdir_patch_digest (patch), zdir_patch_vpath (patch));
    //  Track that we've queued patch for client, so we don't do it twice
    zlist_append (self->client->patches, zdir_patch_dup (patch));
}
Exemple #3
0
static bool
mount_refresh (mount_t *self, server_t *server)
{
    bool activity = false;

    //  Get latest snapshot and build a patches list for any changes
    zdir_t *latest = zdir_new (self->location, NULL);
    zlist_t *patches = zdir_diff (self->dir, latest, self->alias);

    //  Drop old directory and replace with latest version
    zdir_destroy (&self->dir);
    self->dir = latest;

    //  Copy new patches to clients' patches list
    sub_t *sub = (sub_t *) zlist_first (self->subs);
    while (sub) {
        zdir_patch_t *patch = (zdir_patch_t *) zlist_first (patches);
        while (patch) {
            sub_patch_add (sub, patch);
            patch = (zdir_patch_t *) zlist_next (patches);
            activity = true;
        }
        sub = (sub_t *) zlist_next (self->subs);
    }
    
    //  Destroy patches, they've all been copied
    while (zlist_size (patches)) {
        zdir_patch_t *patch = (zdir_patch_t *) zlist_pop (patches);
        zdir_patch_destroy (&patch);
    }
    zlist_destroy (&patches);
    return activity;
}
Exemple #4
0
static void
s_check_directory (s_agent_t *self)
{
    //  Get latest snapshot and build a patches list for any changes
    //  All patches are built using a virtual path starting at "/"
    zdir_t *dir = zdir_new (self->path, NULL);
    zlist_t *patches = zdir_diff (self->dir, dir, "/");

    //  Drop old directory and replace with latest version
    zdir_destroy (&self->dir);
    self->dir = dir;

    while (zlist_size (patches)) {
        zdir_patch_t *patch = (zdir_patch_t *) zlist_pop (patches);
        if (zdir_patch_op (patch) == patch_create) {
            //  Shout new files to DROPS group
            //  Stupidest possible approach: send whole file as one frame
            //  Truncate file at arbitrary limit of 10MB
            zfile_t *file = zdir_patch_file (patch);
            if (zfile_input (file) == 0) {
                zchunk_t *chunk = zfile_read (file, 10 * 1024 * 1024, 0);
                assert (chunk);
                zmsg_t *msg = zmsg_new ();
                zmsg_addstr (msg, "CREATE");
                zmsg_addstr (msg, zdir_patch_vpath (patch));
                zmsg_add (msg, zframe_new (zchunk_data (chunk), zchunk_size (chunk)));
                zchunk_destroy (&chunk);
                zyre_shout (self->zyre, "DROPS", &msg);
            }
        }
        zdir_patch_destroy (&patch);
    }
    zlist_destroy (&patches);
}
Exemple #5
0
void
zdir_patch_test (bool verbose)
{
    printf (" * zdir_patch: ");

    //  @selftest
    zfile_t *file = zfile_new (".", "bilbo");
    assert (file);
    zdir_patch_t *patch = zdir_patch_new (".", file, patch_create, "/");
    assert (patch);
    zfile_destroy (&file);

    file = zdir_patch_file (patch);
    assert (file);
    assert (streq (zfile_filename (file, "."), "bilbo"));
    assert (streq (zdir_patch_vpath (patch), "/bilbo"));
    zdir_patch_destroy (&patch);

#if defined (__WINDOWS__)
    zsys_shutdown();
#endif
    //  @end

    printf ("OK\n");
}
Exemple #6
0
static void
client_destroy (client_t **self_p)
{
    assert (self_p);
    if (*self_p) {
        client_t *self = *self_p;
        zframe_destroy (&self->address);
        fmq_msg_destroy (&self->request);
        fmq_msg_destroy (&self->reply);
        free (self->hashkey);
        while (zlist_size (self->patches)) {                                 
            zdir_patch_t *patch = (zdir_patch_t *) zlist_pop (self->patches);
            zdir_patch_destroy (&patch);                                     
        }                                                                    
        zlist_destroy (&self->patches);                                      
        free (self);
        *self_p = NULL;
    }
}
Exemple #7
0
static void
mount_sub_store (mount_t *self, client_t *client, fmq_msg_t *request)
{
    assert (self);
    assert (self->subs);
    
    //  Store subscription along with any previous ones
    //  Coalesce subscriptions that are on same path
    char *path = fmq_msg_path (request);
    sub_t *sub = (sub_t *) zlist_first (self->subs);
    while (sub) {
        if (client == sub->client) {
            //  If old subscription is superset/same as new, ignore new
            if (strncmp (path, sub->path, strlen (sub->path)) == 0)
                return;
            else
            //  If new subscription is superset of old one, remove old
            if (strncmp (sub->path, path, strlen (path)) == 0) {
                zlist_remove (self->subs, sub);
                sub_destroy (&sub);
                sub = (sub_t *) zlist_first (self->subs);
            }
            else
                sub = (sub_t *) zlist_next (self->subs);
        }
        else
            sub = (sub_t *) zlist_next (self->subs);
    }
    //  New subscription for this client, append to our list
    sub = sub_new (client, path, fmq_msg_cache (request));
    zlist_append (self->subs, sub);

    //  If client requested resync, send full mount contents now
    if (fmq_msg_options_number (client->request, "RESYNC", 0) == 1) {
        zlist_t *patches = zdir_resync (self->dir, self->alias);
        while (zlist_size (patches)) {
            zdir_patch_t *patch = (zdir_patch_t *) zlist_pop (patches);
            sub_patch_add (sub, patch);
            zdir_patch_destroy (&patch);
        }
        zlist_destroy (&patches);
    }
}
Exemple #8
0
//  --------------------------------------------------------------------------
//  Self test of this class
int
zdir_patch_test (bool verbose)
{
    printf (" * zdir_patch: ");

    //  @selftest
    zfile_t *file = zfile_new (".", "bilbo");
    zdir_patch_t *patch = zdir_patch_new (".", file, patch_create, "/");
    zfile_destroy (&file);
    
    file = zdir_patch_file (patch);
    assert (streq (zfile_filename (file, "."), "bilbo"));
    assert (streq (zdir_patch_vpath (patch), "/bilbo"));
    zdir_patch_destroy (&patch);
    //  @end

    printf ("OK\n");
    return 0;
}
Exemple #9
0
zdir_patch_t *
zdir_patch_dup (zdir_patch_t *self)
{
    if (self) {
        zdir_patch_t *copy = (zdir_patch_t *) zmalloc (sizeof (zdir_patch_t));
        if (copy) {
            copy->op = self->op;
            copy->path = strdup (self->path);
            if (copy->path)
                copy->file = zfile_dup (self->file);
            if (copy->file)
                copy->vpath = strdup (self->vpath);
            if (copy->vpath)
                //  Don't recalculate hash when we duplicate patch
                copy->digest = self->digest ? strdup (self->digest) : NULL;

            if (copy->digest == NULL)
                zdir_patch_destroy (&copy);
        }
        return copy;
    }
    else
        return NULL;
}
Exemple #10
0
static void
get_next_patch_for_client (server_t *self, client_t *client)
{
    //  Get next patch for client if we're not doing one already                
    if (client->patch == NULL)                                                  
        client->patch = (zdir_patch_t *) zlist_pop (client->patches);           
    if (client->patch == NULL) {                                                
        client->next_event = finished_event;                                    
        return;                                                                 
    }                                                                           
    //  Get virtual path from patch                                             
    fmq_msg_set_filename (client->reply, zdir_patch_vpath (client->patch));     
                                                                                
    //  We can process a delete patch right away                                
    if (zdir_patch_op (client->patch) == patch_delete) {                        
        fmq_msg_set_sequence (client->reply, client->sequence++);               
        fmq_msg_set_operation (client->reply, FMQ_MSG_FILE_DELETE);             
        client->next_event = send_delete_event;                                 
                                                                                
        //  No reliability in this version, assume patch delivered safely       
        zdir_patch_destroy (&client->patch);                                    
    }                                                                           
    else                                                                        
    if (zdir_patch_op (client->patch) == patch_create) {                        
        //  Create patch refers to file, open that for input if needed          
        if (client->file == NULL) {                                             
            client->file = zfile_dup (zdir_patch_file (client->patch));         
            if (zfile_input (client->file)) {                                   
                //  File no longer available, skip it                           
                zdir_patch_destroy (&client->patch);                            
                zfile_destroy (&client->file);                                  
                client->next_event = next_patch_event;                          
                return;                                                         
            }                                                                   
            client->offset = 0;                                                 
        }                                                                       
        //  Get next chunk for file                                             
        zchunk_t *chunk = zfile_read (client->file, CHUNK_SIZE, client->offset);
        assert (chunk);                                                         
                                                                                
        //  Check if we have the credit to send chunk                           
        if (zchunk_size (chunk) <= client->credit) {                            
            fmq_msg_set_sequence (client->reply, client->sequence++);           
            fmq_msg_set_operation (client->reply, FMQ_MSG_FILE_CREATE);         
            fmq_msg_set_offset (client->reply, client->offset);                 
            fmq_msg_set_chunk (client->reply, zframe_new (                      
                zchunk_data (chunk),                                            
                zchunk_size (chunk)));                                          
                                                                                
            client->offset += zchunk_size (chunk);                              
            client->credit -= zchunk_size (chunk);                              
            client->next_event = send_chunk_event;                              
                                                                                
            //  Zero-sized chunk means end of file                              
            if (zchunk_size (chunk) == 0) {                                     
                zfile_destroy (&client->file);                                  
                zdir_patch_destroy (&client->patch);                            
            }                                                                   
        }                                                                       
        else                                                                    
            client->next_event = no_credit_event;                               
                                                                                
        zchunk_destroy (&chunk);                                                
    }                                                                           
}
Exemple #11
0
///
//  Destroy a patch
QZdirPatch::~QZdirPatch ()
{
    zdir_patch_destroy (&self);
}
Exemple #12
0
void
zdir_test (bool verbose)
{
    printf (" * zdir: ");

    //  @selftest
    // need to create a file in the test directory we're watching
    // in order to ensure the directory exists
    zfile_t *initfile = zfile_new ("./zdir-test-dir", "initial_file");
    assert (initfile);
    zfile_output (initfile);
    fprintf (zfile_handle (initfile), "initial file\n");
    zfile_close (initfile);
    zfile_destroy (&initfile);

    zdir_t *older = zdir_new ("zdir-test-dir", NULL);
    assert (older);
    if (verbose) {
        printf ("\n");
        zdir_dump (older, 0);
    }
    zdir_t *newer = zdir_new (".", NULL);
    assert (newer);
    zlist_t *patches = zdir_diff (older, newer, "/");
    assert (patches);
    while (zlist_size (patches)) {
        zdir_patch_t *patch = (zdir_patch_t *) zlist_pop (patches);
        zdir_patch_destroy (&patch);
    }
    zlist_destroy (&patches);
    zdir_destroy (&older);
    zdir_destroy (&newer);

    zdir_t *nosuch = zdir_new ("does-not-exist", NULL);
    assert (nosuch == NULL);

    // zdir_watch test:
    zactor_t *watch = zactor_new (zdir_watch, NULL);
    assert (watch);

    int synced;
    if (verbose) {
        zsock_send (watch, "s", "VERBOSE");
        synced = zsock_wait(watch);
        assert ( synced == 0);
    }

    zclock_sleep (1001); // wait for initial file to become 'stable'

    zsock_send (watch, "si", "TIMEOUT", 100);
    synced = zsock_wait(watch);
    assert (synced == 0);

    zsock_send (watch, "ss", "SUBSCRIBE", "zdir-test-dir");
    synced = zsock_wait(watch);
    assert(synced == 0);

    zsock_send (watch, "ss", "UNSUBSCRIBE", "zdir-test-dir");
    synced = zsock_wait(watch);
    assert(synced == 0);

    zsock_send (watch, "ss", "SUBSCRIBE", "zdir-test-dir");
    synced = zsock_wait(watch);
    assert(synced == 0);

    zfile_t *newfile = zfile_new ("zdir-test-dir", "test_abc");
    zfile_output (newfile);
    fprintf (zfile_handle (newfile), "test file\n");
    zfile_close (newfile);

    zpoller_t *watch_poll = zpoller_new (watch, NULL);

    // poll for a certain timeout before giving up and failing the test.
    void* polled = zpoller_wait(watch_poll, 1001);
    assert (polled == watch);

    // wait for notification of the file being added
    char *path;
    int rc = zsock_recv (watch, "sp", &path, &patches);
    assert (rc == 0);

    assert (streq (path, "zdir-test-dir"));
    freen (path);

    assert (zlist_size (patches) == 1);

    zdir_patch_t *patch = (zdir_patch_t *) zlist_pop (patches);
    assert (streq (zdir_patch_path (patch), "zdir-test-dir"));

    zfile_t *patch_file = zdir_patch_file (patch);
    assert (streq (zfile_filename (patch_file, ""), "zdir-test-dir/test_abc"));

    zdir_patch_destroy (&patch);
    zlist_destroy (&patches);

    // remove the file
    zfile_remove (newfile);
    zfile_destroy (&newfile);

    // poll for a certain timeout before giving up and failing the test.
    polled = zpoller_wait(watch_poll, 1001);
    assert (polled == watch);

    // wait for notification of the file being removed
    rc = zsock_recv (watch, "sp", &path, &patches);
    assert (rc == 0);

    assert (streq (path, "zdir-test-dir"));
    freen (path);

    assert (zlist_size (patches) == 1);

    patch = (zdir_patch_t *) zlist_pop (patches);
    assert (streq (zdir_patch_path (patch), "zdir-test-dir"));

    patch_file = zdir_patch_file (patch);
    assert (streq (zfile_filename (patch_file, ""), "zdir-test-dir/test_abc"));

    zdir_patch_destroy (&patch);
    zlist_destroy (&patches);

    zpoller_destroy (&watch_poll);
    zactor_destroy (&watch);

    // clean up by removing the test directory.
    zdir_t *testdir = zdir_new ("zdir-test-dir", NULL);
    zdir_remove (testdir, true);
    zdir_destroy (&testdir);

#if defined (__WINDOWS__)
    zsys_shutdown();
#endif
    //  @end

    printf ("OK\n");
}