~mil/mepo

bb51358986ddc0ee662f5159619543c2cf8fce40 — Miles Alan 2 years ago 11b57e5 transfer-canceling
Attempt to solve tile source switching mid-transfer issue

Currently if you switch tilesource while a transfer is ongoing the transfer
will continue on and load (from old source) irregardless; this attempts..
but fails to fix that bug. Produces segfault..
2 files changed, 37 insertions(+), 30 deletions(-)

M src/Mepo.zig
M src/TileCache.zig
M src/Mepo.zig => src/Mepo.zig +2 -2
@@ 283,12 283,12 @@ fn blit_download_bar(mepo: *@This()) !void {
    try mepo.blit_multiline_text(
        0x000000,
        null,
        .{.align_x = .Right },
        .{ .align_x = .Right },
        0,
        @intCast(i32, mepo.win_h) - 20 + 3,
        null,
        "Dl: {d:.2}Mb ",
        .{ @intToFloat(f32, mepo.tile_cache.byte_counter) / 1024 / 1024  },
        .{@intToFloat(f32, mepo.tile_cache.byte_counter) / 1024 / 1024},
    );
    try mepo.blit_multiline_text(
        0x000000,

M src/TileCache.zig => src/TileCache.zig +35 -28
@@ 188,10 188,10 @@ fn curl_setopt(client: *curl.CURL, opt: c_int, value: anytype) !void {
    }
}

fn curl_msg_to_coords(tile_cache: *@This(), msg: *curl.CURLMsg) ?types.XYZ {
fn curl_client_to_coords(tile_cache: *@This(), client: *curl.CURL) ?types.XYZ {
    var it = tile_cache.transfer_map.iterator();
    while (it.next()) |kv| {
        if (kv.value_ptr.*.client == msg.*.easy_handle) {
        if (kv.value_ptr.*.client == client) {
            return kv.value_ptr.*.coords;
        }
    }


@@ 218,19 218,21 @@ fn transfer_complete(tile_cache: *@This(), msg: *curl.CURLMsg) !void {
            utildbg.log("Curl timed out for msg: {}\n", .{msg});
        },
        .CURLE_OK => {
            if (tile_cache.curl_msg_to_coords(msg)) |coords| {
                const transfer_datum = tile_cache.transfer_map.get(coords).?;
                const datum_array = transfer_datum.data_arraylist.items;
                tile_cache.byte_counter += transfer_datum.data_arraylist.items.len;

                if (tile_cache.cache_dir) |cache_dir| {
                    // Save to FS
                    const path = try png_path(tile_cache.allocator, tile_cache.source_url.?, coords);
                    try cache_dir.writeFile(path, datum_array);
                }
                if (tile_cache.transfer_map.get(coords).?.load_to_texture) {
                    // Load to surface
                    _ = try tile_cache.load_data_to_texture(coords, datum_array);
            if (msg.*.easy_handle) |client| {
                if (tile_cache.curl_client_to_coords(client)) |coords| {
                    const transfer_datum = tile_cache.transfer_map.get(coords).?;
                    const datum_array = transfer_datum.data_arraylist.items;
                    tile_cache.byte_counter += transfer_datum.data_arraylist.items.len;

                    if (tile_cache.cache_dir) |cache_dir| {
                        // Save to FS
                        const path = try png_path(tile_cache.allocator, tile_cache.source_url.?, coords);
                        try cache_dir.writeFile(path, datum_array);
                    }
                    if (tile_cache.transfer_map.get(coords).?.load_to_texture) {
                        // Load to surface
                        _ = try tile_cache.load_data_to_texture(coords, datum_array);
                    }
                }
            } else {
                utildbg.log("Failed to find coordinates associated with downloaded data?\n", .{});


@@ 247,19 249,17 @@ fn transfer_complete(tile_cache: *@This(), msg: *curl.CURLMsg) !void {
// SDL resize (refresh event). By effect, if tile is loaded in texture
// map rendering thread fetches and updates it; if CURLE_OK wasn't
// there - the item will get repushed back into queue
fn transfer_cleanup(tile_cache: *@This(), msg: *curl.CURLMsg) !void {
    if (tile_cache.curl_msg_to_coords(msg)) |coords| {
        const transfer_datum = tile_cache.transfer_map.get(coords).?;
        const datum_array = transfer_datum.data_arraylist.items;
fn transfer_cleanup(tile_cache: *@This(), client: *curl.CURL) !void {
    try curl_errorcheck(curl.curl_multi_remove_handle(tile_cache.curl_multi, client));
    curl.curl_easy_cleanup(client);

    if (tile_cache.curl_client_to_coords(client)) |coords| {
        tile_cache.transfer_map.get(coords).?.data_arraylist.deinit();
        _ = tile_cache.transfer_map.swapRemove(coords);
        tile_cache.allocator.destroy(transfer_datum);
        if (tile_cache.transfer_map.get(coords)) |transfer_datum|
            tile_cache.allocator.destroy(transfer_datum);
    }

    try curl_errorcheck(curl.curl_multi_remove_handle(tile_cache.curl_multi, msg.*.easy_handle));

    curl.curl_easy_cleanup(msg.*.easy_handle);

    if (tile_cache.n_current_transfers > 0) {
        tile_cache.n_current_transfers -= 1;
    }


@@ 322,9 322,11 @@ pub fn download_loop(tile_cache: *@This(), graphical_mode: bool) void {
                    tile_cache.transfer_complete(msg) catch |err| {
                        utildbg.log("Failed to successfully complete transfer: {}!\n", .{err});
                    };
                    tile_cache.transfer_cleanup(msg) catch |err| {
                        utildbg.log("Failed to successfully cleanup transfer: {}!\n", .{err});
                    };
                    if (msg.*.easy_handle) |client| {
                        tile_cache.transfer_cleanup(client) catch |err| {
                            utildbg.log("Failed to successfully cleanup transfer: {}!\n", .{err});
                        };
                    }
                    lock.release();
                },
                else => {


@@ 387,9 389,14 @@ pub fn set_cache_dir(tile_cache: *@This(), path: [:0]const u8) !void {
///
/// Caller passed ptr url may be safely freed
pub fn set_cache_url(tile_cache: *@This(), url: [:0]const u8) !void {
    // Empty Cache
    const lock = tile_cache.mutex.acquire();
    defer lock.release();

    // Empty texture map, queue, and current transfers
    tile_cache.texture_map.clearAndFree();
    tile_cache.queue_lifo.clearAndFree();
    for (tile_cache.transfer_map.values()) |transfer|
        try tile_cache.transfer_cleanup(transfer.client);

    // Set new URL
    if (tile_cache.source_url) |present_source_url| {