00:44
_whitelogger has joined #picolisp
01:29
andyjpb has quit [Ping timeout: 264 seconds]
01:43
karswell has joined #picolisp
01:46
karswell has quit [Remote host closed the connection]
01:47
karswell has joined #picolisp
01:49
karswell has quit [Remote host closed the connection]
01:50
karswell has joined #picolisp
02:02
karswell_ has joined #picolisp
02:05
karswell has quit [Ping timeout: 265 seconds]
02:13
karswell_ is now known as karswell
02:20
karswell has quit [Remote host closed the connection]
02:21
karswell has joined #picolisp
04:41
_whitelogger has joined #picolisp
05:15
<
Regenaxer >
Hi aw-!
05:25
<
aw- >
i'm a bit confused about the "Persistence (external symbols)" doc
05:25
<
aw- >
it shows how to (put) stuff in the *DB
05:25
<
aw- >
but it doesn't show how to retrieve them
05:25
<
aw- >
other than using (show)
05:26
<
aw- >
I figured i need (get) to retrieve, but the syntax is unclear
05:26
<
Regenaxer >
There is no explicit retrieval
05:26
<
Regenaxer >
Just use it
05:27
<
Regenaxer >
One level above the raw external symbols is the E/R level
05:27
<
Regenaxer >
There you have classes, and indexes to find things
05:28
<
aw- >
i have no idea what that means
05:28
<
aw- >
i (put) a few things in the DB
05:29
<
aw- >
how do I retrieve them?
05:29
<
aw- >
ex: (put *DB 'a 1) (put *DB 'b 2) ... how do I get the value 2 from 'b ?
05:29
<
aw- >
(get *DB 'b) doesn't work
05:29
<
Regenaxer >
You always know the root object *DB == {1}
05:30
<
Regenaxer >
the put's and get's look fine
05:30
<
Regenaxer >
you need (commit) before you close the session
05:31
<
aw- >
yes actually i'm using (put!)
05:31
<
Regenaxer >
(put *DB 'a 1) is the same as (put '{1} 'a 1)
05:32
<
Regenaxer >
So it is all correct
05:32
<
aw- >
hmmm.. ok i must be doing something wrong
05:32
<
Regenaxer >
What means "(get *DB 'b) doesn't work" ?
05:32
<
Regenaxer >
gives NIL?
05:35
<
aw- >
I was doing (get *DB (pack Var1 Var2)) .. doesnt work
05:36
<
Regenaxer >
yes, needs internal symbols
05:37
<
Regenaxer >
pointer equality in 'get'
05:39
yunfan has quit [Ping timeout: 248 seconds]
05:41
yunfan has joined #picolisp
05:41
<
aw- >
(unless (get *DB 'a) ...) doesn't work either
05:42
<
Regenaxer >
Must work
05:44
<
aw- >
this doesn't work with strings?
05:44
<
aw- >
ex, if a property is "a" instead of 'a ?
05:45
<
Regenaxer >
As I said above, properties in general
*should* be internal symbols
05:45
<
aw- >
i need to intern each property?
05:45
<
Regenaxer >
transients work, but only in the same scope
05:45
<
Regenaxer >
pointer equality in 'get'
05:46
<
Regenaxer >
on pil64 also short numbers work, they are also "pointer equal"
05:47
<
Regenaxer >
I usually avoid numbers as properties though
05:47
<
aw- >
ok so this means, if I intern the symbols then i can't have duplicates ?
05:47
<
Regenaxer >
How do you mean that?
05:48
<
aw- >
in normal databases you can (optionally) have multiple keys with the same name
05:48
<
Regenaxer >
You mean non-uniqe indexes?
05:48
<
Regenaxer >
Nothing to do with properties of symbols
05:49
<
Regenaxer >
You can't have 2 entries in a C struct with the same name either
05:49
<
Regenaxer >
properties are like structs in some sense
05:50
<
Regenaxer >
I think you misunderstood something basic about pil DBs
05:50
<
Regenaxer >
The properties are not to
*search* the DB
05:50
<
Regenaxer >
they are attributes of objects
05:51
<
aw- >
yes i don't know about pil DBs.. first time using
05:51
<
Regenaxer >
good, take time :)
05:51
<
aw- >
ok so if they are not to search the DB, how do I search the DB?
05:52
<
Regenaxer >
I think you should read the tutorial
05:52
<
Regenaxer >
and doc/select.html
05:52
<
Regenaxer >
select is the main workhorse of searching
05:53
<
Regenaxer >
But you find also objects with (db 'var '+Cls ...)
05:53
<
Regenaxer >
or (collect 'var '+Cls ...)
05:53
<
Regenaxer >
or via direct +Link's and +Joint's between objects
05:56
<
Regenaxer >
There is also 'init' + 'step', and 'iter' and 'scan' on the lower levels (direct B-Tree access)
05:57
<
aw- >
i don't see why i can't use the properties of a symbol for searching.. is it slow?
05:58
<
Regenaxer >
no, the fastest
05:58
<
Regenaxer >
+Link's and +Joint's use them
05:58
<
aw- >
if I do: (put *DB 'a 1) (put *DB 'b 2) (put *DB 'c 3) .. what's wrong with using (get *DB 'c) ?
05:59
<
aw- >
you said: "Regenaxer: The properties are not to
*search* the DB"
05:59
<
Regenaxer >
Sigh, it
*does* work
05:59
<
Regenaxer >
this is not a search but a direct access
06:00
<
Regenaxer >
Searching means to find an object by the
*value* of its property
06:00
<
aw- >
oh.. no i'm not doing that
06:00
<
aw- >
i'm "searching" by property name
06:00
<
Regenaxer >
*DB is known, no need to search for it
06:02
<
aw- >
would be it be inefficient to have say... 1000 symbols in my DB? better to have 1 symbol with 1000 properties?
06:04
<
Regenaxer >
1000 is nothing
06:04
<
Regenaxer >
talk about 1000000000
06:05
<
Regenaxer >
Ah, 1000 properties?
06:06
<
Regenaxer >
That's bad
06:06
<
Regenaxer >
They are searched linearly
06:06
<
Regenaxer >
It means an
*object* with 1000 attributes, not a good idea
06:07
<
aw- >
interesting..
06:07
<
Regenaxer >
But a typical application has millions of objects typically
06:07
<
Regenaxer >
Thats is no problem
06:07
<
aw- >
ok so (put *DB 'abcdef 1000) <-- (1000th entry) would be bad?
06:07
<
aw- >
what do you mean by "objects" and "attributes" ?
06:07
<
aw- >
these are not the words in the doc
06:08
<
Regenaxer >
"objects" = "symbols" in pil
06:08
<
Regenaxer >
and "attributes" are properties
06:08
<
Regenaxer >
Both words are used I think
06:08
<
aw- >
so 1000 objects = OK, 1000 attributes = NO
06:08
<
Regenaxer >
A symbol is called an "object" if it has classes
06:09
<
Regenaxer >
You can try
06:09
<
aw- >
ok so back to my example
06:09
<
aw- >
ok so (put *DB 'abcdef 1000) <-- (1000th entry) would be bad?
06:09
<
Regenaxer >
such an object would just be big
06:09
<
Regenaxer >
takes time and space to load into memory
06:10
<
Regenaxer >
I don't understand: (put *DB 'abcdef 1000) <-- (1000th entry)
06:10
<
aw- >
but i thought interning many symbols is considered bad in pil
06:10
<
Regenaxer >
*external* symbols
06:10
<
Regenaxer >
not internal
06:11
<
aw- >
well.. that's ripe for confusion .. it's not obvious what is the meaning of "interning external symbols"
06:11
<
Regenaxer >
You should forget about "(put *DB" something
06:11
<
Regenaxer >
not done in applications
06:11
<
aw- >
it's in the tutorial!
06:11
<
Regenaxer >
Well, yes, external symbols have their symbol table in memory
06:12
<
Regenaxer >
but these are only for the
*currently* loaded symbols
06:12
<
Regenaxer >
"(put *DB" is the low level, yes
06:12
<
aw- >
so if I "forget" about (put *DB) , what should I use instead?
06:13
<
Regenaxer >
Entities and relations
06:13
<
aw- >
i dont need relations
06:13
<
Regenaxer >
I think you did
*not* read the tutorial
06:13
<
aw- >
i just want to maintain a list of key/value across parent/child processes
06:13
<
aw- >
this is become too complex for what i want
06:14
<
Regenaxer >
If you have only key/value pairs then you only need a tree
06:14
<
Regenaxer >
and use 'store' and 'fetch' directly
06:14
<
aw- >
i'm not trying to do a DB maintenance or relationship/entity mapping or any fancy stuff here
06:15
<
Regenaxer >
Then I can't help you
06:15
<
aw- >
well yes actually, i think 'store and 'fetch are the functions I was looking for
06:18
<
Regenaxer >
you can use NIL for the tree if the root of the thee should be *DB
06:18
<
Regenaxer >
in store and fetch
06:18
<
tankf33der >
aw-: good startpoint:
06:19
<
Regenaxer >
In trees the keys can be anything, not only internal symbols
06:20
<
Regenaxer >
tankf33der, thanks, but perhaps still too complicated example
06:21
<
tankf33der >
top task
06:21
<
Regenaxer >
Just (store NIL "key" "value" (1 . 256))
06:21
<
Regenaxer >
(fetch NIL "key")
06:21
<
tankf33der >
school marks db on lists and db
06:22
<
Regenaxer >
yes, very nice
06:22
<
Regenaxer >
Uses E/R so not what aw- wants to use it seems
06:27
<
tankf33der >
latest ios 11.4, safari crash on picolisp documentation frames
06:27
<
tankf33der >
i need tricky steps how to read reference fetch func
06:29
<
Regenaxer >
'fetch' is a low-level function
06:29
<
Regenaxer >
Normal apps use it seldom
06:29
<
Regenaxer >
I do have some raw trees in applications, mainly for logging
06:30
<
Regenaxer >
Where it is too expensive to build full objects
06:35
<
tankf33der >
i wish sometimes inmplement all this on picodb
06:36
<
aw- >
ok i think (fetch) and (store) with a NIL tree is simplest
06:36
<
Regenaxer >
tankf33der, yep :)
06:36
<
Regenaxer >
aw-, yes, seems fit for your use case
06:37
<
aw- >
Regenaxer: thanks
06:38
<
aw- >
can you also confirm if it will be slow to retrieve 1 of 1000 keys using (fetch) ?
06:38
<
Regenaxer >
1000 is not much
06:39
<
Regenaxer >
You should use a larger block size if you expect large trees
06:40
<
Regenaxer >
default is only 256
06:40
<
Regenaxer >
so if keys and values are long, only a few nodes fit into a block
06:40
<
Regenaxer >
But 30 should fit, so searcng 1000 only involves 2 levels
06:41
<
Regenaxer >
ideally reading 2 blocks
06:41
<
Regenaxer >
yes, these are bytes
06:41
<
Regenaxer >
see ref of 'pool'
06:41
<
Regenaxer >
you specify the block size there
06:43
<
aw- >
"defaulting to (2) (for a single file with a 256 byte block size"
06:43
<
aw- >
what does this mean?
06:43
<
aw- >
2 for a single file?
06:44
<
Regenaxer >
no, 2 means 256
06:44
<
aw- >
so 4 would be 512 ?
06:44
<
Regenaxer >
a single file with 1024 blocks would be (4)
06:45
<
aw- >
with (store) do i also need to specify that same blocksize used in (pool) ?
06:45
<
Regenaxer >
Unfortunately yes, as 'store' does not know the context (as the E/R system does)
06:46
<
Regenaxer >
So in an application I create a dummy-relation for such trees
06:47
<
Regenaxer >
eg (rel log (+Swap +Any))
06:47
<
Regenaxer >
But in your simple case just pass it to 'store'
06:48
<
aw- >
yeah... tbh i don't really understand the concept of block size for the DB
06:49
<
aw- >
if my key/value pairs can have a max length of 1KB (1024 bytes), what should I use?
06:49
<
aw- >
(pool "db" (8)) ?
06:49
<
Regenaxer >
External symbols are simply written to blocks in PLIO format
06:49
<
Regenaxer >
oh, thats very long for a single key/value
06:50
<
Regenaxer >
The max size does not matter, but the average
06:51
<
Regenaxer >
It is good if 30 or perhaps.100 key/value pairs fit into a block
06:51
<
Regenaxer >
It is a B-Tree
06:51
<
Regenaxer >
one block is one node ideally
06:51
<
aw- >
30-100 seems arbitrary
06:51
<
Regenaxer >
can be more
06:52
<
aw- >
if each key is 512bytes and each value is 512 bytes, how would I choose the value for (pool) ?
06:52
<
Regenaxer >
*inside* a tree node the search is with 'rank', aka linear
06:53
<
Regenaxer >
Then 32 k
06:53
<
Regenaxer >
would be (9)
06:54
<
Regenaxer >
Do you really have such long keys??
06:54
<
Regenaxer >
If the
*values* are big, then better use separate objects to store them
06:54
<
Regenaxer >
to avoid having to load
*all* for every search
06:55
<
Regenaxer >
And the keys are better broken down if speed is really an issue
06:55
<
Regenaxer >
Not for 1000 entries perhaps
06:55
<
Regenaxer >
How long are the keys on average?
06:56
<
Regenaxer >
You talked of 512 bytes
06:56
<
aw- >
what's the max length of a filesystem dir/path ?
06:57
<
Regenaxer >
I see, then I would index the path elements
06:57
<
aw- >
255 bytes is max length on XFS
06:57
<
Regenaxer >
But for a first try, just use, say, 6
06:58
<
aw- >
so probably the default 256 bytes is fine for the path, assuming it's used as a key
06:58
<
Regenaxer >
I think it can be more than 256 on modern OSs
06:59
<
Regenaxer >
I think a typical path length is below 100
06:59
<
aw- >
oh sorry, 255 bytes is the filename length
06:59
<
aw- >
not the full path
06:59
<
Regenaxer >
So with (6) or 4 KiB you get enough space
07:00
<
Regenaxer >
still 20 or 40 nodes
07:00
<
Regenaxer >
My recommendation is (6) :)
07:01
<
aw- >
(pool "db" (6)) ?
07:01
<
Regenaxer >
Feels ok
07:02
<
Regenaxer >
If the block size is too big, too much unnecessary stuff is loaded on each access
07:02
<
aw- >
yeah... kinda hard to predict
07:03
<
Regenaxer >
and if too small some nodes may overflow to 2 blocks needing more reads
07:03
<
Regenaxer >
In practice no big difference perhap
07:03
<
Regenaxer >
Depends how often accessed etc
07:04
<
Regenaxer >
I would not worry too much here
07:04
<
aw- >
perhaps I can set an artificial limit to 256 bytes, so i'll never have a key longer than 256?
07:04
<
Regenaxer >
You can tune later
07:04
<
aw- >
or is the 256 key+value ?
07:04
<
Regenaxer >
yes both
07:05
<
Regenaxer >
I would inspect the tree with typical data with (edit *DB)
07:06
<
Regenaxer >
then click on the objects down into the tree nodes
07:06
<
Regenaxer >
I'm doing that often to get an impression
07:09
<
aw- >
i don't know if that'll be worth the effort for now
07:09
<
aw- >
i'll start with smaller values and wait a while before checking if it should be higher
07:13
<
Regenaxer >
yes, good way
08:04
alexshendi has quit [Ping timeout: 264 seconds]
08:14
karswell has quit [Read error: Connection reset by peer]
08:15
karswell has joined #picolisp
08:56
<
Regenaxer >
I think aw- wants something more low-level
08:56
<
Regenaxer >
only key/value pairs
08:57
<
beneroth >
probably, though he should now there is more :)
08:58
<
beneroth >
key/value stores are a fashion. but all in all they're weaker then DBs with schema. and pilDB has the flexibility of a dumb key/value store while having graph db features, I would say :P
08:59
<
aw- >
it's not a fashion statement
08:59
<
Regenaxer >
correct. He could probably extend his model later if needed
08:59
<
beneroth >
sure. that was not a saying about you
08:59
<
beneroth >
I guess you have a key/value use case, like config or so?
08:59
<
aw- >
i'm doing cache lookups, how else would you store that?
08:59
<
beneroth >
so you have another backend behind it?
09:00
<
Regenaxer >
Sometimes raw tree access is useful. I do that occasionally too
09:00
<
aw- >
? just picolisp fetching/storing keys from a cache
09:00
<
aw- >
fetching values based on the key
09:01
<
aw- >
i can't think of a more optimal storage mechanism, no need for relational complexity
09:02
<
beneroth >
not without looking at the data, T. I think I would try to maybe split it up in different types/groups, if it makes sense with the data
09:02
<
aw- >
it's just key/value
09:03
<
aw- >
and it doesn't even need to persist, so i'm using it exclusively in memory, without commit
09:04
<
beneroth >
what about (idx) (not DB functionality) ?
09:04
<
aw- >
if i want to (fork) then i can commit and fetch from the fork
09:04
<
beneroth >
T, good concept
09:05
<
Regenaxer >
Ah, not persistent? OK, understand
09:06
<
Regenaxer >
Such an tree also makes sense (over idx) if it does not fit into memory in total
09:11
<
beneroth >
though this use case is a bit of a weakness, afaik you can't just (wipe) the longest-not-used external symbols from memory (because access is not tracked)
09:12
<
beneroth >
special case
09:12
<
Regenaxer >
But you can clean the tree with 'prune'
09:12
<
Regenaxer >
I do that for very big imports
09:13
<
beneroth >
hm right. how does (prune) track accesses ?
09:14
<
beneroth >
ah I see. inbuilt into fetch and store, when *Prune global exists
09:14
<
beneroth >
so tracking can easily be enabled. be it with prune or another scheme.
09:14
<
beneroth >
another = custom
09:16
<
beneroth >
yeah perfect for aw-s scenario.
09:16
<
beneroth >
thanks, you too
09:16
<
Regenaxer >
I call prune after commits, and then sometimes (gc 0) to free heap space
09:16
<
beneroth >
thanks, you two
09:18
<
Regenaxer >
But prune is seldom needed, only in long periods of imports
09:19
<
Regenaxer >
During normal operation the automatic gc cleans up also all tree nodes
09:20
<
Regenaxer >
In an import they are always referred to, so the they don't become garbage
09:20
<
Regenaxer >
afp a while
09:22
<
aw- >
beneroth: no need to wipe
09:54
orivej has quit [Ping timeout: 245 seconds]
11:46
orivej has joined #picolisp
12:09
orivej has quit [Ping timeout: 260 seconds]
12:33
orivej has joined #picolisp
12:41
andyjpb has joined #picolisp
12:53
<
aw- >
in the ref docs: (let sym 'any . prg) -> any .. what does "-> any" mean ?
12:53
<
aw- >
shouldn't it be the return value?
12:53
<
Regenaxer >
The 'let' expression returns anything
12:53
<
aw- >
but return value of 'let' is prg, not any
12:54
<
Regenaxer >
no, prg runs and gives any
12:54
<
aw- >
oh right right
12:54
<
aw- >
yes i forgot that
12:55
<
aw- >
is there a shorthand for doing something like: (Let Myvar Lst (fun1) (fun2) (fun3) Myvar) ?
12:56
<
Regenaxer >
yes, in some cases 'prog1'
12:56
<
Regenaxer >
(prog1 (foo) (println @) (inc @))
12:57
<
Regenaxer >
will return the result of (foo)
12:57
<
Regenaxer >
same as
12:57
<
Regenaxer >
(let X (foo) (println X) (inc X) x)
12:57
<
Regenaxer >
(let X (foo) (println X) (inc X) X)
12:58
<
aw- >
that's exactly what i was looking for
13:01
<
aw- >
in (prog1), @ is always bound to the result of 'any1 ?
13:02
<
Regenaxer >
Must go to the station, fetch my daughter
13:03
<
aw- >
ah yes it's in the docs!, case, casq, etc...
16:21
<
beneroth >
"If your application uses GPGME your application is safe. Fortunately
16:21
<
beneroth >
users should make sure to use "set crypt_use_gpgme".
16:21
<
beneroth >
most modern mail readers use GPGME, including GpgOL and KMail. Mutt
16:32
beneroth has quit [Quit: Verlassend]
16:51
andyjpb has quit [Quit: Leaving.]
18:06
clacke[m] has quit [Ping timeout: 256 seconds]
18:07
fwirt[m] has quit [Ping timeout: 276 seconds]
19:50
alexshendi has joined #picolisp
20:30
fwirt[m] has joined #picolisp
20:45
clacke[m] has joined #picolisp
20:50
orivej has quit [Ping timeout: 256 seconds]
21:35
kakobrekla has joined #picolisp
22:15
orivej has joined #picolisp
22:44
alexshendi has quit [Ping timeout: 256 seconds]