count a negative cache entry as cache - we will never see data from this provider
This commit is contained in:
parent
cc5030d70c
commit
a15b9cf471
1 changed files with 43 additions and 0 deletions
43
src/cache/store.zig
vendored
43
src/cache/store.zig
vendored
|
|
@ -1236,7 +1236,18 @@ pub const Store = struct {
|
|||
}
|
||||
|
||||
/// Check if candle metadata is fresh using the embedded `#!expires=` directive.
|
||||
///
|
||||
/// A negative cache entry ("this symbol has no candle data on any
|
||||
/// provider") counts as fresh, so the portfolio price fast-path
|
||||
/// (`isCandleCacheFresh`) does not re-fetch it on every run. The
|
||||
/// marker lives in `candles_daily.srf` - written by `writeNegative`
|
||||
/// on a permanent NotFound, or synced verbatim from a `ZFIN_SERVER` -
|
||||
/// and is honored there directly because `candles_meta.srf` is never
|
||||
/// created for a no-data symbol. Cleared by `--refresh-data=force` /
|
||||
/// `cache clear`.
|
||||
pub fn isCandleMetaFresh(self: *Store, symbol: []const u8) bool {
|
||||
if (self.isNegative(symbol, .candles_daily)) return true;
|
||||
|
||||
const raw = self.readRaw(symbol, .candles_meta) catch return false;
|
||||
const data = raw orelse return false;
|
||||
defer self.allocator.free(data);
|
||||
|
|
@ -3332,6 +3343,38 @@ test "Store.read does not self-heal an intact candles_daily" {
|
|||
try std.testing.expectError(error.FileNotFound, std.Io.Dir.cwd().access(std.testing.io, torn_dir_path, .{}));
|
||||
}
|
||||
|
||||
test "isCandleMetaFresh: negative candles_daily counts as fresh even with no candles_meta" {
|
||||
const io = std.testing.io;
|
||||
var tmp = std.testing.tmpDir(.{});
|
||||
defer tmp.cleanup();
|
||||
const dir_path = try tmp.dir.realPathFileAlloc(io, ".", testing.allocator);
|
||||
defer testing.allocator.free(dir_path);
|
||||
|
||||
var store = Store.init(io, testing.allocator, dir_path);
|
||||
|
||||
// A symbol with no candle data on any provider (e.g. crypto like
|
||||
// DOGE-USD that Tiingo can't serve): the negative marker is written
|
||||
// to candles_daily.srf and candles_meta.srf is never created. It must
|
||||
// read as fresh so the portfolio price fast-path doesn't re-fetch it
|
||||
// (and re-sync from a ZFIN_SERVER) on every run.
|
||||
try store.ensureSymbolDir("DOGE-USD");
|
||||
store.writeNegative("DOGE-USD", .candles_daily);
|
||||
try std.testing.expect(store.isCandleMetaFresh("DOGE-USD"));
|
||||
|
||||
// A real, unexpired candles_meta is still fresh...
|
||||
try store.ensureSymbolDir("AAA");
|
||||
try store.writeRaw("AAA", .candles_meta, "#!srfv1\n#!expires=9999999999\n#!created=1777000000\nlast_close:num:1.0,last_date::2026-04-22\n");
|
||||
try std.testing.expect(store.isCandleMetaFresh("AAA"));
|
||||
|
||||
// ...and a past-due one is not.
|
||||
try store.ensureSymbolDir("BBB");
|
||||
try store.writeRaw("BBB", .candles_meta, "#!srfv1\n#!expires=1000000000\n#!created=999999999\nlast_close:num:1.0,last_date::2026-04-22\n");
|
||||
try std.testing.expect(!store.isCandleMetaFresh("BBB"));
|
||||
|
||||
// A symbol with no candle files at all is not fresh.
|
||||
try std.testing.expect(!store.isCandleMetaFresh("ZZZ"));
|
||||
}
|
||||
|
||||
test "Store.dataTypeFor maps model types correctly" {
|
||||
try std.testing.expectEqual(DataType.candles_daily, Store.dataTypeFor(Candle));
|
||||
try std.testing.expectEqual(DataType.dividends, Store.dataTypeFor(Dividend));
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue