mirror of
https://github.com/9001/copyparty.git
synced 2025-08-17 09:02:15 -06:00
fuse: cache options
This commit is contained in:
parent
ec29b59d1e
commit
0ea7881652
|
@ -194,7 +194,7 @@ class Gateway(object):
|
||||||
def download_file_range(self, path, ofs1, ofs2):
|
def download_file_range(self, path, ofs1, ofs2):
|
||||||
web_path = self.quotep("/" + "/".join([self.web_root, path])) + "?raw"
|
web_path = self.quotep("/" + "/".join([self.web_root, path])) + "?raw"
|
||||||
hdr_range = "bytes={}-{}".format(ofs1, ofs2 - 1)
|
hdr_range = "bytes={}-{}".format(ofs1, ofs2 - 1)
|
||||||
log("downloading {}".format(hdr_range))
|
log("downloading {:4.0f}K, {}".format((ofs2 - ofs1) / 1024.0, hdr_range))
|
||||||
|
|
||||||
r = self.sendreq("GET", web_path, headers={"Range": hdr_range})
|
r = self.sendreq("GET", web_path, headers={"Range": hdr_range})
|
||||||
if r.status != http.client.PARTIAL_CONTENT:
|
if r.status != http.client.PARTIAL_CONTENT:
|
||||||
|
@ -277,9 +277,11 @@ class Gateway(object):
|
||||||
|
|
||||||
|
|
||||||
class CPPF(Operations):
|
class CPPF(Operations):
|
||||||
def __init__(self, base_url):
|
def __init__(self, base_url, dircache, filecache):
|
||||||
self.gw = Gateway(base_url)
|
self.gw = Gateway(base_url)
|
||||||
self.junk_fh_ctr = 3
|
self.junk_fh_ctr = 3
|
||||||
|
self.n_dircache = dircache
|
||||||
|
self.n_filecache = filecache
|
||||||
|
|
||||||
self.dircache = []
|
self.dircache = []
|
||||||
self.dircache_mtx = threading.Lock()
|
self.dircache_mtx = threading.Lock()
|
||||||
|
@ -289,12 +291,22 @@ class CPPF(Operations):
|
||||||
|
|
||||||
info("up")
|
info("up")
|
||||||
|
|
||||||
|
def _describe(self):
|
||||||
|
msg = ""
|
||||||
|
for n, cn in enumerate(self.filecache):
|
||||||
|
cache_path, cache1 = cn.tag
|
||||||
|
cache2 = cache1 + len(cn.data)
|
||||||
|
msg += "\n#{} = {} {} {}\n{}\n".format(
|
||||||
|
n, cache1, len(cn.data), cache2, cache_path
|
||||||
|
)
|
||||||
|
return msg
|
||||||
|
|
||||||
def clean_dircache(self):
|
def clean_dircache(self):
|
||||||
"""not threadsafe"""
|
"""not threadsafe"""
|
||||||
now = time.time()
|
now = time.time()
|
||||||
cutoff = 0
|
cutoff = 0
|
||||||
for cn in self.dircache:
|
for cn in self.dircache:
|
||||||
if now - cn.ts > 1:
|
if now - cn.ts > self.n_dircache:
|
||||||
cutoff += 1
|
cutoff += 1
|
||||||
else:
|
else:
|
||||||
break
|
break
|
||||||
|
@ -411,7 +423,18 @@ class CPPF(Operations):
|
||||||
|
|
||||||
continue
|
continue
|
||||||
|
|
||||||
raise Exception("what")
|
msg = "cache fallthrough\n{} {} {}\n{} {} {}\n{} {} --\n".format(
|
||||||
|
get1,
|
||||||
|
get2,
|
||||||
|
get2 - get1,
|
||||||
|
cache1,
|
||||||
|
cache2,
|
||||||
|
cache2 - cache1,
|
||||||
|
get1 - cache1,
|
||||||
|
get2 - cache2,
|
||||||
|
)
|
||||||
|
msg += self._describe()
|
||||||
|
raise Exception(msg)
|
||||||
|
|
||||||
if car and cdr:
|
if car and cdr:
|
||||||
dbg("<cache> have both")
|
dbg("<cache> have both")
|
||||||
|
@ -420,7 +443,9 @@ class CPPF(Operations):
|
||||||
if len(ret) == get2 - get1:
|
if len(ret) == get2 - get1:
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
raise Exception("{} + {} != {} - {}".format(len(car), len(cdr), get2, get1))
|
msg = "{} + {} != {} - {}".format(len(car), len(cdr), get2, get1)
|
||||||
|
msg += self._describe()
|
||||||
|
raise Exception(msg)
|
||||||
|
|
||||||
elif cdr:
|
elif cdr:
|
||||||
h_end = get1 + (get2 - get1) - len(cdr)
|
h_end = get1 + (get2 - get1) - len(cdr)
|
||||||
|
@ -482,18 +507,20 @@ class CPPF(Operations):
|
||||||
|
|
||||||
cn = CacheNode([path, h_ofs], buf)
|
cn = CacheNode([path, h_ofs], buf)
|
||||||
with self.filecache_mtx:
|
with self.filecache_mtx:
|
||||||
if len(self.filecache) > 6:
|
if len(self.filecache) >= self.n_filecache:
|
||||||
self.filecache = self.filecache[1:] + [cn]
|
self.filecache = self.filecache[1:] + [cn]
|
||||||
else:
|
else:
|
||||||
self.filecache.append(cn)
|
self.filecache.append(cn)
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
def readdir(self, path, fh=None):
|
def _readdir(self, path, fh=None):
|
||||||
path = path.strip("/")
|
path = path.strip("/")
|
||||||
log("readdir [{}] [{}]".format(path, fh))
|
log("readdir [{}] [{}]".format(path, fh))
|
||||||
|
|
||||||
ret = self.gw.listdir(path)
|
ret = self.gw.listdir(path)
|
||||||
|
if not self.n_dircache:
|
||||||
|
return ret
|
||||||
|
|
||||||
with self.dircache_mtx:
|
with self.dircache_mtx:
|
||||||
cn = CacheNode(path, ret)
|
cn = CacheNode(path, ret)
|
||||||
|
@ -502,6 +529,9 @@ class CPPF(Operations):
|
||||||
|
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
|
def readdir(self, path, fh=None):
|
||||||
|
return [".", ".."] + self._readdir(path, fh)
|
||||||
|
|
||||||
def read(self, path, length, offset, fh=None):
|
def read(self, path, length, offset, fh=None):
|
||||||
path = path.strip("/")
|
path = path.strip("/")
|
||||||
|
|
||||||
|
@ -516,9 +546,10 @@ class CPPF(Operations):
|
||||||
if file_sz == 0 or offset >= ofs2:
|
if file_sz == 0 or offset >= ofs2:
|
||||||
return b""
|
return b""
|
||||||
|
|
||||||
# toggle cache here i suppose
|
if not self.n_filecache:
|
||||||
# return self.get_cached_file(path, offset, ofs2, file_sz)
|
return self.gw.download_file_range(path, offset, ofs2)
|
||||||
return self.gw.download_file_range(path, offset, ofs2)
|
|
||||||
|
return self.get_cached_file(path, offset, ofs2, file_sz)
|
||||||
|
|
||||||
def getattr(self, path, fh=None):
|
def getattr(self, path, fh=None):
|
||||||
log("getattr [{}]".format(path))
|
log("getattr [{}]".format(path))
|
||||||
|
@ -532,7 +563,7 @@ class CPPF(Operations):
|
||||||
|
|
||||||
if not path:
|
if not path:
|
||||||
ret = self.gw.stat_dir(time.time())
|
ret = self.gw.stat_dir(time.time())
|
||||||
dbg("=" + repr(ret))
|
# dbg("=" + repr(ret))
|
||||||
return ret
|
return ret
|
||||||
|
|
||||||
cn = self.get_cached_dir(dirpath)
|
cn = self.get_cached_dir(dirpath)
|
||||||
|
@ -541,11 +572,11 @@ class CPPF(Operations):
|
||||||
dents = cn.data
|
dents = cn.data
|
||||||
else:
|
else:
|
||||||
log("cache miss")
|
log("cache miss")
|
||||||
dents = self.readdir(dirpath)
|
dents = self._readdir(dirpath)
|
||||||
|
|
||||||
for cache_name, cache_stat, _ in dents:
|
for cache_name, cache_stat, _ in dents:
|
||||||
if cache_name == fname:
|
if cache_name == fname:
|
||||||
dbg("=" + repr(cache_stat))
|
# dbg("=" + repr(cache_stat))
|
||||||
return cache_stat
|
return cache_stat
|
||||||
|
|
||||||
log("=404 ({})".format(path))
|
log("=404 ({})".format(path))
|
||||||
|
@ -646,7 +677,9 @@ class CPPF(Operations):
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
try:
|
try:
|
||||||
local, remote = sys.argv[1:]
|
local, remote = sys.argv[1:3]
|
||||||
|
filecache = 7 if len(sys.argv) <= 3 else int(sys.argv[3])
|
||||||
|
dircache = 1 if len(sys.argv) <= 4 else float(sys.argv[4])
|
||||||
except:
|
except:
|
||||||
where = "local directory"
|
where = "local directory"
|
||||||
if WINDOWS:
|
if WINDOWS:
|
||||||
|
@ -654,6 +687,8 @@ def main():
|
||||||
|
|
||||||
print("need arg 1: " + where)
|
print("need arg 1: " + where)
|
||||||
print("need arg 2: root url")
|
print("need arg 2: root url")
|
||||||
|
print("optional 3: num files in filecache (7)")
|
||||||
|
print("optional 4: num seconds / dircache (1)")
|
||||||
print()
|
print()
|
||||||
print("example:")
|
print("example:")
|
||||||
print(" copyparty-fuse.py ./music http://192.168.1.69:3923/music/")
|
print(" copyparty-fuse.py ./music http://192.168.1.69:3923/music/")
|
||||||
|
@ -666,7 +701,7 @@ def main():
|
||||||
os.system("")
|
os.system("")
|
||||||
|
|
||||||
FUSE(
|
FUSE(
|
||||||
CPPF(remote),
|
CPPF(remote, dircache, filecache),
|
||||||
local,
|
local,
|
||||||
foreground=True,
|
foreground=True,
|
||||||
nothreads=True,
|
nothreads=True,
|
||||||
|
|
71
scripts/fusefuzz.py
Executable file
71
scripts/fusefuzz.py
Executable file
|
@ -0,0 +1,71 @@
|
||||||
|
#!/usr/bin/env python3
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
"""
|
||||||
|
mkdir -p /dev/shm/fusefuzz/{r,v}
|
||||||
|
PYTHONPATH=.. python3 -m copyparty -v /dev/shm/fusefuzz/r::r -i 127.0.0.1
|
||||||
|
../bin/copyparty-fuse.py /dev/shm/fusefuzz/v http://127.0.0.1:3923/ 2 0
|
||||||
|
(d="$PWD"; cd /dev/shm/fusefuzz && "$d"/fusefuzz.py)
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
for n in range(5):
|
||||||
|
with open(f"r/{n}", "wb") as f:
|
||||||
|
f.write(b"h" * n)
|
||||||
|
|
||||||
|
for fsz in range(1024 * 1024 * 2 - 3, 1024 * 1024 * 2 + 3):
|
||||||
|
with open("r/f", "wb", fsz) as f:
|
||||||
|
f.write(b"\xab" * fsz)
|
||||||
|
|
||||||
|
for rsz in range(62, 66):
|
||||||
|
ofslist = [0, 1, 2]
|
||||||
|
for n in range(3):
|
||||||
|
ofslist.append(fsz - n)
|
||||||
|
ofslist.append(fsz - (rsz * 1 + n))
|
||||||
|
ofslist.append(fsz - (rsz * 2 + n))
|
||||||
|
|
||||||
|
for ofs0 in ofslist:
|
||||||
|
for shift in range(-3, 3):
|
||||||
|
print(f"fsz {fsz} rsz {rsz} ofs {ofs0} shift {shift}")
|
||||||
|
ofs = ofs0
|
||||||
|
if ofs < 0 or ofs >= fsz:
|
||||||
|
continue
|
||||||
|
|
||||||
|
for n in range(1, 3):
|
||||||
|
with open(f"v/{n}", "rb") as f:
|
||||||
|
f.read()
|
||||||
|
|
||||||
|
prev_ofs = -99
|
||||||
|
with open("r/f", "rb", rsz) as rf:
|
||||||
|
with open("v/f", "rb", rsz) as vf:
|
||||||
|
while True:
|
||||||
|
ofs += shift
|
||||||
|
if ofs < 0 or ofs > fsz or ofs == prev_ofs:
|
||||||
|
break
|
||||||
|
|
||||||
|
prev_ofs = ofs
|
||||||
|
|
||||||
|
if ofs != rf.tell():
|
||||||
|
rf.seek(ofs)
|
||||||
|
vf.seek(ofs)
|
||||||
|
|
||||||
|
rb = rf.read(rsz)
|
||||||
|
vb = vf.read(rsz)
|
||||||
|
|
||||||
|
print(
|
||||||
|
f"fsz {fsz} rsz {rsz} ofs {ofs0} shift {shift} ofs {ofs} = {len(rb)}"
|
||||||
|
)
|
||||||
|
|
||||||
|
if rb != vb:
|
||||||
|
raise Exception(f"{len(rb)} != {len(vb)}")
|
||||||
|
|
||||||
|
if not rb:
|
||||||
|
break
|
||||||
|
|
||||||
|
ofs += len(rb)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
Loading…
Reference in a new issue