예제 #1
0
파일: fcgi-utils.c 프로젝트: michals/sx
static void send_error_helper(const char sep, int errnum, const char *message) {
    CGI_PRINTF("%c\"ErrorMessage\":", sep);
    json_send_qstring(message);
    if (errnum == 500 || errnum == 400) {
        if (message)
            WARN("HTTP %d: %s", errnum, message);
        CGI_PUTS(",\"ErrorDetails\":");
        json_send_qstring(msg_log_end());
    }
    CGI_PUTS(",\"NodeId\":");
    const sx_node_t *me = sx_hashfs_self(hashfs);
    json_send_qstring(me ? sx_node_uuid(me)->string : "<UNKNOWN>");
    CGI_PUTS(",\"ErrorId\":");
    json_send_qstring(msg_get_id());
    CGI_PUTC('}');
}
예제 #2
0
파일: blockmgr.c 프로젝트: s3v3ns/sx
static int unbump_revs(struct revunbump_data_t *unb) {
    int64_t revs[MAX_UNBUMPS];
    sqlite3_stmt *q;
    char *qry = NULL;
    const void *tgt;
    unsigned int i, qlen = 0, qat = 0;
    int64_t unbid;
    const sx_node_t *target, *me;
    int r, err = 0, remote;

    q = unb->quget_hi;
    sqlite3_reset(q);
    if(qbind_blob(q, ":oldtarget", (const void *)&unb->last_target, sizeof(unb->last_target)))
	return -1; /* Error */
    r = qstep(q);
    if(r == SQLITE_DONE) {
	q = unb->quget_lo;
	sqlite3_reset(q);
	if(qbind_blob(q, ":oldtarget", (const void *)&unb->last_target, sizeof(unb->last_target)))
	    return -1; /* Error */
	r = qstep(q);
	if(r == SQLITE_DONE)
	    return 0; /* Work complete */
    }
    if(r != SQLITE_ROW)
	return -1; /* Error */

    unbid = sqlite3_column_int64(q, 0);
    tgt = sqlite3_column_blob(q, 3);
    if(!tgt || sqlite3_column_bytes(q, 3) != sizeof(unb->last_target.binary)) {
	WARN("Removing unbid %lld with bogus target", (long long)unbid);
	sqlite3_reset(q);
	return unbump_unq(unb, unbid);
    }
    uuid_from_binary(&unb->last_target, tgt);

    target = sx_nodelist_lookup(sx_hashfs_all_nodes(unb->hashfs, NL_NEXTPREV), &unb->last_target);
    if(!target) {
	DEBUG("Removing unbid %lld for target node %s which is no longer a member", (long long)unbid, unb->last_target.string);
	sqlite3_reset(q);
	return unbump_unq(unb, unbid);
    }

    if(sx_hashfs_is_node_ignored(unb->hashfs, &unb->last_target)) {
	/* These will be sent once there is a replacement */
	DEBUG("Skipping requests for unbid %lld for target node %s which is no longer a member", (long long)unbid, unb->last_target.string);
	sqlite3_reset(q);
	return 0; /* Work complete */
    }

    me = sx_hashfs_self(unb->hashfs);
    remote = sx_node_cmp(me, target);
    if(!remote && sx_hashfs_revision_op_begin(unb->hashfs)) {
	WARN("Failed to start revision operation: %s", msg_get_reason());
	sqlite3_reset(q);
	return -1; /* Error */
    }
    for(i=0; i<MAX_UNBUMPS;) {
	const sx_hash_t *revid;
	unsigned int bs = sqlite3_column_int(q, 2);

	if(sx_hashfs_check_blocksize(bs))
	    WARN("Removing unbid %lld with invalid block size %u", (long long)unbid, bs);
	else if(!(revid = sqlite3_column_blob(q, 1)) || sqlite3_column_bytes(q, 1) != sizeof(*revid))
	    WARN("Removing unbid %lld with bogus revision ID", (long long)unbid);
	else if(!(tgt = sqlite3_column_blob(q, 3)) || sqlite3_column_bytes(q, 3) != sizeof(unb->last_target.binary))
	    WARN("Removing unbid %lld with bogus target", (long long)unbid);
        else if(memcmp(tgt, &unb->last_target.binary, sizeof(unb->last_target.binary)))
	    break;
	else if(remote) {
	    /* Remote target */
	    if(qlen - qat < sizeof(*revid) * 2 + sizeof(",\"\":") + 32) {
		/* Make room for hex encoded rev, size and json glue */
		qlen += 1024;
		qry = wrap_realloc_or_free(qry, qlen);
		if(!qry) {
		    WARN("Unable to allocate query");
		    err = 1;
		    break;
		}
	    }
	    
	    qry[qat] = qat ? ',' : '{';
	    qry[qat+1] = '"';
	    qat += 2;
	    bin2hex(revid, sizeof(*revid), &qry[qat], qlen - qat);
	    qat += sizeof(*revid)*2;
	    qat += snprintf(&qry[qat], qlen - qat,"\":%u", bs);
	} else {
	    /* Local target */
	    if(sx_hashfs_revision_op(unb->hashfs, bs, revid, -1) != OK) {
		WARN("Failed to unbump local revision");
		err = 1;
		break;
	    }
	}
	revs[i++] = sqlite3_column_int64(q, 0);

	r = qstep(q);
	if(r == SQLITE_ROW)
	    continue;
	else if(r != SQLITE_DONE) {
	    WARN("Failed to retrieve next revision");
	    err = 1;
	}
	break;
    }

    sqlite3_reset(q);

    if(!remote) {
	/* Commit local revision ops... */
	if(!err && sx_hashfs_revision_op_commit(unb->hashfs)) {
	    WARN("Failed to commit revision operation: %s", msg_get_reason());
	    err = 1;
	}
	/* ... or rollback on error */
	if(err)
	    sx_hashfs_revision_op_rollback(unb->hashfs);
    }

    if(err) {
	free(qry);
	return -1; /* Error */
    }

    if(remote && qry) {
	sxi_conns_t *clust = sx_hashfs_conns(unb->hashfs);
	sxc_client_t *sx = sx_hashfs_client(unb->hashfs);
	sxi_hostlist_t hlist;
	int qret;

	sxi_hostlist_init(&hlist);
	if(qlen - qat < 2) {
	    qry = wrap_realloc_or_free(qry, qlen + 2);
	    if(!qry) {
		WARN("Unable to allocate query");
		return -1; /* Error */
	    }
	}
	qry[qat] = '}';
	qry[qat+1] = '\0';

	if(sxi_hostlist_add_host(sx, &hlist, sx_node_internal_addr(target))) {
	    WARN("Unable to allocate hostlist");
	    free(qry);
	    return -1; /* Error */
	}

	qret = sxi_cluster_query(clust, &hlist, REQ_PUT, ".blockrevs/remove", qry, strlen(qry), NULL, NULL, NULL);
	free(qry);
	qry = NULL;
	sxi_hostlist_empty(&hlist);
	if(qret != 200) {
	    WARN("Unbump request failed for %s (%s): HTTP status %d", unb->last_target.string, sx_node_internal_addr(target), qret);
	    return -1;
	}
    }

    free(qry);
    while(i--)
	unbump_unq(unb, revs[i]);

    return 1; /* Some work done */

}
예제 #3
0
파일: blockmgr.c 프로젝트: s3v3ns/sx
static int schedule_blocks_sfq(struct blockmgr_data_t *q) {
    sx_uuid_t target_uuid;
    sqlite3_stmt *qget;
    int ret = 0, r;

    DEBUG("in %s", __func__);
    qget = q->qget_first_hi;
    if(qbind_int64(qget, ":flow", q->last_flowid)) {
	WARN("Error retrieving master block from queue");
	return -1;
    }
    r = qstep(qget);
    if(r == SQLITE_DONE) {
	qget = q->qget_first_lo;
	if(qbind_int64(qget, ":flow", q->last_flowid)) {
	    WARN("Error retrieving master block from queue");
	    return -1;
	}
	r = qstep(qget);
    }
    if(r == SQLITE_DONE) {
	DEBUG("No blocks in the queue");
	return 0;
    }
    if(r != SQLITE_ROW) {
	WARN("Error retrieving master block from queue");
	return -1;
    }

    do {
	int64_t push_id;
	const void *p;
	int i;

	/* SELECT id, flow, block[, size, node] */
	push_id = sqlite3_column_int64(qget, 0);
	q->last_flowid = sqlite3_column_int64(qget, 1);

	if(!ret) {
	    /* First block is the "master" and dictates blocksize and target node */
	    q->blocksize = sqlite3_column_int(qget, 3);
	    if(sx_hashfs_check_blocksize(q->blocksize)) {
		WARN("Removing block with invalid blocksize %u", q->blocksize);
		sqlite3_reset(qget);
		blockmgr_del_xfer(q, push_id);
		return schedule_blocks_sfq(q);
	    }

	    p = sqlite3_column_blob(qget, 4);
	    if(sqlite3_column_bytes(qget, 4) != sizeof(target_uuid.binary)) {
		WARN("Removing block with invalid target node UUID");
		sqlite3_reset(qget);
		blockmgr_del_xfer(q, push_id);
		return schedule_blocks_sfq(q);
	    }
	    uuid_from_binary(&target_uuid, p);
	    if(!(q->target = sx_nodelist_lookup(sx_hashfs_effective_nodes(q->hashfs, NL_NEXT), &target_uuid))) {
		DEBUG("Removing transfer to non existing (possibly ignored) node %s", target_uuid.string);
		sqlite3_reset(qget);
		blockmgr_del_xfer(q, push_id);
		return schedule_blocks_sfq(q);
	    }
	    if(!sx_node_cmp(q->target, sx_hashfs_self(q->hashfs))) {
		WARN("Removing transfer to self");
		sqlite3_reset(qget);
		blockmgr_del_xfer(q, push_id);
		return schedule_blocks_sfq(q);
	    }

	    DEBUG("Selected master block for transfer bs: %u, node: %s", q->blocksize, target_uuid.string);
	}

	p = sqlite3_column_blob(qget, 2);
	if(sqlite3_column_bytes(qget, 2) != SXI_SHA1_BIN_LEN) {
	    if(!ret) {
		/* Remove "master" block from queue */
		WARN("Removing block with invalid hash");
		sqlite3_reset(qget);
		blockmgr_del_xfer(q, push_id);
		return schedule_blocks_sfq(q);
	    } else /* Or silently skip slaves (they'll be pruned in the subsequent loops) */
		continue;
	}

	q->hashlist.ids[ret] = push_id;
	q->hashlist.havehs[ret] = 0;
	memcpy(&q->hashlist.binhs[ret], p, SXI_SHA1_BIN_LEN);
	sqlite3_reset(qget);

	if(!ret && qstep_noret(q->qwipesched)) {
	    sqlite3_reset(qget);
	    WARN("Failed to wipe schedule");
	    return -1;
	}
	if(qbind_int64(q->qaddsched, ":pushid", push_id) ||
	   qstep_noret(q->qaddsched)) {
	    WARN("Failed to schedule block transfer");
	    return -1;
	}

	/*
	do {
	    char hexh[SXI_SHA1_BIN_LEN * 2 + 1];
	    sxi_bin2hex(&q->hashlist.binhs[ret], SXI_SHA1_BIN_LEN, hexh);
	    INFO("Block %s scheduled for transfer", hexh);
	} while(0);
	*/

	ret++;
	if(ret >= DOWNLOAD_MAX_BLOCKS)
	    break;

	for(i = 0; i<2; i++) {
	    /* Failure is not severe here: we just ship what we have scheduled so far and call it a day */
	    qget = (i == 0) ? q->qget_next_hi : q->qget_next_lo;
	    if(qbind_int64(qget, ":flow", q->last_flowid) ||
	       qbind_int(qget, ":size", q->blocksize) ||
	       qbind_blob(qget, ":node", target_uuid.binary, sizeof(target_uuid.binary))) {
		WARN("Error retrieving next slave block from queue");
		r = SQLITE_DONE;
		break;
	    }
	    r = qstep(qget);
	    if(r == SQLITE_ROW)
		break;
	    if(r != SQLITE_DONE) {
		WARN("Error retrieving next slave block from queue");
		break;
	    }
	}
    } while(r == SQLITE_ROW);

    q->hashlist.nblocks = ret;
    DEBUG("Successfully scheduled %d blocks for transfer", ret);
    return ret;
}