Add debug logging to cache lookup
This commit is contained in:
21
README.md
21
README.md
@@ -36,9 +36,12 @@ Interactive docs: http://localhost:8100/docs
|
|||||||
| POST | `/runs` | Start a rendering run |
|
| POST | `/runs` | Start a rendering run |
|
||||||
| GET | `/runs` | List all runs |
|
| GET | `/runs` | List all runs |
|
||||||
| GET | `/runs/{run_id}` | Get run status |
|
| GET | `/runs/{run_id}` | Get run status |
|
||||||
|
| DELETE | `/runs/{run_id}` | Delete a run |
|
||||||
| GET | `/cache` | List cached content hashes |
|
| GET | `/cache` | List cached content hashes |
|
||||||
| GET | `/cache/{hash}` | Download cached content |
|
| GET | `/cache/{hash}` | Download cached content |
|
||||||
|
| DELETE | `/cache/{hash}` | Delete cached content |
|
||||||
| POST | `/cache/import?path=` | Import local file to cache |
|
| POST | `/cache/import?path=` | Import local file to cache |
|
||||||
|
| POST | `/cache/upload` | Upload file to cache |
|
||||||
| GET | `/assets` | List known assets |
|
| GET | `/assets` | List known assets |
|
||||||
|
|
||||||
### Start a run
|
### Start a run
|
||||||
@@ -55,6 +58,24 @@ curl -X POST http://localhost:8100/runs \
|
|||||||
curl http://localhost:8100/runs/{run_id}
|
curl http://localhost:8100/runs/{run_id}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### Delete a run
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X DELETE http://localhost:8100/runs/{run_id} \
|
||||||
|
-H "Authorization: Bearer <token>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Failed runs can always be deleted. Completed runs can only be deleted if their outputs haven't been published to L2.
|
||||||
|
|
||||||
|
### Delete cached content
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X DELETE http://localhost:8100/cache/{hash} \
|
||||||
|
-H "Authorization: Bearer <token>"
|
||||||
|
```
|
||||||
|
|
||||||
|
Note: Items that are inputs/outputs of runs, or published to L2, cannot be deleted.
|
||||||
|
|
||||||
## Storage
|
## Storage
|
||||||
|
|
||||||
- **Cache**: `~/.artdag/cache/` (content-addressed files)
|
- **Cache**: `~/.artdag/cache/` (content-addressed files)
|
||||||
|
|||||||
@@ -243,33 +243,46 @@ class L1CacheManager:
|
|||||||
|
|
||||||
def get_by_content_hash(self, content_hash: str) -> Optional[Path]:
|
def get_by_content_hash(self, content_hash: str) -> Optional[Path]:
|
||||||
"""Get cached file path by content_hash."""
|
"""Get cached file path by content_hash."""
|
||||||
|
logger.info(f"get_by_content_hash({content_hash[:16]}...) - cache_dir={self.cache_dir}, nodes_dir={self.cache.cache_dir}")
|
||||||
|
|
||||||
# Check index first (new cache structure)
|
# Check index first (new cache structure)
|
||||||
node_id = self._content_index.get(content_hash)
|
node_id = self._content_index.get(content_hash)
|
||||||
if node_id:
|
if node_id:
|
||||||
|
logger.info(f" Found in content_index: node_id={node_id[:16]}...")
|
||||||
path = self.cache.get(node_id)
|
path = self.cache.get(node_id)
|
||||||
if path and path.exists():
|
if path and path.exists():
|
||||||
|
logger.info(f" Found via index: {path}")
|
||||||
return path
|
return path
|
||||||
|
logger.info(f" Index entry but path not found: {path}")
|
||||||
|
|
||||||
# For uploads, node_id == content_hash, so try direct lookup
|
# For uploads, node_id == content_hash, so try direct lookup
|
||||||
# This works even if cache index hasn't been reloaded
|
# This works even if cache index hasn't been reloaded
|
||||||
|
logger.info(f" Trying direct lookup with content_hash as node_id...")
|
||||||
path = self.cache.get(content_hash)
|
path = self.cache.get(content_hash)
|
||||||
|
logger.info(f" cache.get({content_hash[:16]}...) returned: {path}")
|
||||||
if path and path.exists():
|
if path and path.exists():
|
||||||
|
logger.info(f" Found via direct lookup: {path}")
|
||||||
self._content_index[content_hash] = content_hash
|
self._content_index[content_hash] = content_hash
|
||||||
self._save_content_index()
|
self._save_content_index()
|
||||||
return path
|
return path
|
||||||
|
|
||||||
# Scan cache entries (fallback for new structure)
|
# Scan cache entries (fallback for new structure)
|
||||||
|
logger.info(f" Trying find_by_content_hash...")
|
||||||
entry = self.cache.find_by_content_hash(content_hash)
|
entry = self.cache.find_by_content_hash(content_hash)
|
||||||
if entry and entry.output_path.exists():
|
if entry and entry.output_path.exists():
|
||||||
|
logger.info(f" Found via scan: {entry.output_path}")
|
||||||
self._content_index[content_hash] = entry.node_id
|
self._content_index[content_hash] = entry.node_id
|
||||||
self._save_content_index()
|
self._save_content_index()
|
||||||
return entry.output_path
|
return entry.output_path
|
||||||
|
|
||||||
# Check legacy location (files stored directly as CACHE_DIR/{content_hash})
|
# Check legacy location (files stored directly as CACHE_DIR/{content_hash})
|
||||||
legacy_path = self.cache_dir / content_hash
|
legacy_path = self.cache_dir / content_hash
|
||||||
|
logger.info(f" Checking legacy path: {legacy_path}, exists={legacy_path.exists()}")
|
||||||
if legacy_path.exists() and legacy_path.is_file():
|
if legacy_path.exists() and legacy_path.is_file():
|
||||||
|
logger.info(f" Found at legacy location: {legacy_path}")
|
||||||
return legacy_path
|
return legacy_path
|
||||||
|
|
||||||
|
logger.info(f" NOT FOUND anywhere")
|
||||||
return None
|
return None
|
||||||
|
|
||||||
def has_content(self, content_hash: str) -> bool:
|
def has_content(self, content_hash: str) -> bool:
|
||||||
|
|||||||
36
server.py
36
server.py
@@ -280,6 +280,42 @@ async def root():
|
|||||||
return HOME_HTML
|
return HOME_HTML
|
||||||
|
|
||||||
|
|
||||||
|
@app.get("/debug/cache/{content_hash}")
|
||||||
|
async def debug_cache(content_hash: str):
|
||||||
|
"""Debug endpoint to check cache status for a content hash."""
|
||||||
|
import os
|
||||||
|
|
||||||
|
result = {
|
||||||
|
"content_hash": content_hash,
|
||||||
|
"cache_dir": str(cache_manager.cache_dir),
|
||||||
|
"nodes_dir": str(cache_manager.cache.cache_dir),
|
||||||
|
"in_content_index": content_hash in cache_manager._content_index,
|
||||||
|
"node_id_from_index": cache_manager._content_index.get(content_hash),
|
||||||
|
}
|
||||||
|
|
||||||
|
# Check various locations
|
||||||
|
locations = {
|
||||||
|
"legacy_direct": cache_manager.cache_dir / content_hash,
|
||||||
|
"nodes_dir": cache_manager.cache.cache_dir / content_hash,
|
||||||
|
}
|
||||||
|
|
||||||
|
for name, path in locations.items():
|
||||||
|
result[f"{name}_path"] = str(path)
|
||||||
|
result[f"{name}_exists"] = path.exists()
|
||||||
|
if path.exists() and path.is_dir():
|
||||||
|
result[f"{name}_contents"] = [f.name for f in path.iterdir()]
|
||||||
|
|
||||||
|
# Check if artdag cache has it
|
||||||
|
result["artdag_cache_get"] = str(cache_manager.cache.get(content_hash))
|
||||||
|
|
||||||
|
# Check via cache_manager
|
||||||
|
found_path = cache_manager.get_by_content_hash(content_hash)
|
||||||
|
result["cache_manager_path"] = str(found_path) if found_path else None
|
||||||
|
result["has_content"] = cache_manager.has_content(content_hash)
|
||||||
|
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
@app.post("/runs", response_model=RunStatus)
|
@app.post("/runs", response_model=RunStatus)
|
||||||
async def create_run(request: RunRequest, username: str = Depends(get_required_user)):
|
async def create_run(request: RunRequest, username: str = Depends(get_required_user)):
|
||||||
"""Start a new rendering run. Requires authentication."""
|
"""Start a new rendering run. Requires authentication."""
|
||||||
|
|||||||
Reference in New Issue
Block a user