You are not logged in.
It was a copy and paste issue, fixed it.
Is the style of the solution correct? Registering the class and using ParseNewInstance?
Here is my response to my question. I do not know if this is the best option though.
procedure TItemReader.ReadItem(var Context: TJsonParserContext; Data: pointer);
var
S: PUTF8Char;
SP: RawUTF8;
L: integer;
C: TItemClass;
Instance: TObject;
begin
Result := nil;
P := Context.Json;
OldP := P;
P := JsonObjectItem(P, 'CustomClass');
if P = nil then
raise Exception.Create('Invalid Item');
JSONRetrieveStringField(P, S, L, False);
SetString(SP, S, L);
case SP of
'ItemA': C := TItemA;
'ItemB': C := TItemB;
else
raise Exception.Create('Unknown Item: ' + SP);
end;
Context.Info := Rtti.RegisterClass(C);
Instance := TRttiJson(Context.Info).ParseNewInstance(Context);
end;And register it like this:
TRttiJson.RegisterCustomSerializer(TypeInfo(TItem), @ReadItem, nil); I had a code with mORMot1 like:
TTextWriter.RegisterCustomJSONSerializer(TypeInfo(TItems), @ReadItem, nil);and
function TItemReader.ReadItem(P: PUTF8Char; var AValue; out AValid: boolean): PUTF8Char;
var
V: TObject absolute AValue;
OldP, S: PUTF8Char;
SP: RawUTF8;
L: integer;
begin
AValid := False;
Result := nil;
if P = nil then
Exit;
OldP := P;
P := JsonObjectItem(P, 'CustomClass');
if P = nil then
raise Exception.Create('Invalid Item');
JSONRetrieveStringField(P, S, L, False);
SetString(SP, S, L);
case SP of
'ItemA': V := TItemA.Create;
'ItemB': V := TItemB.Create;
else
raise Exception.Create('Unknown Item: ' + SP);
end;
AValid := True;
Result := JSONToObject(AValue, OldP, AValid, nil, JSONTOOBJECT_TOLERANTOPTIONS);
end;and now with mORMot2, I can not convert it.
I thought I should do this but it leads to unknown errors.
function TItemReader.ReadItem(P: PUTF8Char; var AValue; out AValid: boolean): PUTF8Char;
var
V: TObject absolute AValue;
OldP, S: PUTF8Char;
SP: RawUTF8;
L: integer;
begin
AValid := False;
Result := nil;
P := Context.Json;
OldP := P;
P := JsonObjectItem(P, 'CustomClass');
if P = nil then
raise Exception.Create('Invalid Item');
JSONRetrieveStringField(P, S, L, False);
SetString(SP, S, L);
case SP of
'ItemA': V := TItemA.Create;
'ItemB': V := TItemB.Create;
else
raise Exception.Create('Unknown Item: ' + SP);
end;
AValid := True;
Context.Json := JSONToObject(Instance, Context.Json, Context.Valid, nil, JSONTOOBJECT_TOLERANTOPTIONS);
end;What is the correct way to unserializing and array of classes?
Note: I can not use ParseNewObject, as the CustomClass property may not be the first properties and some other custom needs.
Now it is working. Thank you.
Just checked again,
The error can be reproduced with with either the latest mORMot2 or sqlite revision 3.37.2 and FPC trunk of now.
Most mORMot tests fails, it seems a memory problem.
One interesting thing for me is that, why such an error is not detected by some catch and can mess around with other parts of code, even the parts that seem unrelated.
I was suspected of patching RTL, but activating NOPATCHRTL, makes everything worse.
I was using an old Trunk with mORMot2 from two weeks ago (sqlite revision 3.37.2 172d789404d400ed60447a2b757c5ac770906ae9) and everything was fine, but I pulled mORMot2 as habit and memory crash ...
So I updated my Trunk and now the problem I reported.
Unfortunately I'm stuck with Trunk (3.3.1) for generics and I cannot go back.
I recently pulled mORMot2 and ran into some exceptions when setting FPC's internal string methods.I updated FPC and Lazarus to Trunk from Git and now it runs, but my SQLite Vtab codes are not working or buggy.
Just adding a useless log code like WriteLn(RawUtf8(argv^[0])); after begin of xConnect makes it work.
It solves the issue in some projects but not in others. Note that the RawUtf8 cast is the solving part, as reading the argv or WriteLn on their own does not change anything.
It is a weird case, so I'd like to know what the best version to try.
I am working on Windows 64bit and the stable version of FPC is working with the latest mORMot2, but I cannot use the stable version as the Generics code is lagging behind.
I'd appreciate any suggestions.
Very interesting article.
I like to know more about how you debug these problems, like the TAsyncServer case.
Thank you!
Hi,
TSynQueue.Count method uses ReadOnlyLock, and it makes problems when the Queue is shared between threads that are using the count while others are reading from or writing into it.
It was a weird error to find but in some cases it trough exceptions and maybe it is a good idea to use ReadWriteLock instead in Count. In my case it solved the issue like this:
with Queue do
try
Safe.ReadWriteLock;
QueueCount := Queue.Count;
finally
Safe.ReadWriteUnLock;
end; Hi,
I wanted to check and compile static files, and as noted there are notes and scripts for many of them like libquickjs. But I could not find the code for some files like r crc32c64.obj or sha512-x64sse4.obj.
Are those available ?
Thank you for the clarification. Interesting as always.
I noticed that when I include mormot.core.data, it makes comparing string (A=B) fast. Checking that subject I found that mormot.core.rtti patches the fpc_ansistr_compare and it is very fast, excellent.
The question for me is that why mORMot do not use this functions for other parts (eg DynArray) and uses StrComp instead?
procedure Test;
var
I, C: Int64;
A, B: String;
T: TLocalPrecisionTimer;
begin
A := 'Hello World';
UniqueString(A);
B := 'Hello World';
UniqueString(B);
C := 0;
T := TLocalPrecisionTimer.CreateAndStart;
for I := 1 to 50 * 1000 * 1000 do
if A = B then //_ansistr_compare_equal //95ms
//if SortDynArrayString(A, B) = 0 then
//if StrComp(PChar(A), PChar(B)) = 0 then //367ms
C += 1;
Writeln(C, ' ', T.Stop);
end;
Thank you for the updates.
Great!
Yes mORMot is the very fast and a blog post as an update to previous ones seems nice. May I suggest having an independent demo that clearly shows the benefits and speed? It helps to answer questions like this topic.
Also it may be a good idea to add JsonTools (from this topic) too as it is very clean and seems fast.
Topic: https://forum.lazarus.freepascal.org/in … opic=46533
PS, can you please update the TDynArrayHasher compile issue with trunk? It helps someone like me to keep up with your fast updates while maintaining daily codes.
Thanks for the update. Checked it and it works near 20GB/s! Great!
About TDynArrayHasher, it still does not work for FPC even with the new parenthesis, it seems an @ is needed.
I tried to minimize the problem in a new project and included mORMot define too, it compiles correctly, the problem is only happening in the unit. Sorry for the trouble, but I think it worth to be able to compile with the latest version of FPC.
Thanks for the update.
About Trunk, it let me try mORMot code with latest FPC updates as I use mORMot a lot for daily tasks like array, dictionary, Unicode, file and json. And until the latest update to the TDynArrayHasher it worked just fine and passed all the test so it may be a good idea to keep it running and testing latest things.
It is the case for V2, I agree with you on V1 of mORMot as it was always problematic to use it with Trunk. But your updates to V2 made it very compatible and comfortable to use.
Very nice.
But I can not compile it with the latest Trunk FPC on Win10 X64. IsValidUtf8Avx2 crashes.
mORMot test fail too on this function.
By disabling the AVX version, Pas version works 3GB/s for me on i9.
Unrelated note: In TDynArrayHasher.FindOrNew, checking Assigned(Compare) fails on FPC trunk. Previous versions work without problem.
I think you may get better results trying to rewrite it and prevent dependency.
The validate_utf8 function is light and needs no memory using SIMD. More info: https://lemire.me/blog/2018/05/16/valid … -per-byte/
But as far as JSON needs, mORMot SAX approach uses no memory, but simdjson builds a DOM-like info that takes much (near 5X I think) more memory.
Thank you. I will try to match the style better next time.
Nothing much, that was my fault anyway.
I made the pull request, please review.
Yes and I tried to propose a pull request but it had conflicts so I need to redo and check again.
As I added Configuration Options comments too.
Great. I inherited TSqlite3LibraryStatic with and override the BeforeInitialization with this:
procedure TCustomSqlite3LibraryStatic.BeforeInitialization;
begin
sqlite3.config(SQLITE_CONFIG_MEMSTATUS, Integer(True));
inherited BeforeInitialization;
end; Now it works.
I will make a pull request for the config comments and show how it must be used to prevent future misunderstandings.
@ab, can you please let me know if you meant ForceToUseSharedMemoryManager or something else? I tired to disable it and again SQLite report zero.
As documented (https://www.sqlite.org/c3ref/c_status_malloc_count.html) SQLITE_STATUS_MEMORY_USED retunes xSize results and I checked your versions, the result is non zero, so the issue may be somewhere else?
I like to have a check on memory usage and it seems the standard way for SQLite.
Bare metal, Windows.
Here is the new results in an i9:
https://gist.github.com/OkobaPatino/12b … 86fc1dfe06
Thank you.
Great update. Thank you ab!
I've checked your changes and tests, and rerun my test in an i3 too. Without SetCapacity results are 2X faster for Add() and 1.3X for find. Also Find() is almost the same with and without SetCapacity. It's great!
Two questions, is there a count limit for TSynDictionary / TDynArrayHasher? What will be the O for more than 10M?
I was reporting string dictionary without set capacity, surprised that why the new algorithm is not faster.
This time I did an another test: https://gist.github.com/OkobaPatino/cec … 358984f5c5
These are the result of latest mORMot, latest FPC, Windows and i9.
Remarks:
In increasing string AesNiHash32 is slower, near 25% with SetCapacity and near 50% without SetCapacity.
In random GUID AesNiHash32 is a bit slower.
If dictionary capacity is set beforehand, Add (400%) and Find (25%) is faster, no matter the Hasher.
Questions:
Find is slower when you do not set capacity before hand. Why?
Can I ask where much less collisions come to play with AesNiHash32 as it is always slower than crc32c?
BTW It would be nice to have the ability of choosing the Hasher of the dictionary now that we have more options.
I've experienced 2X slowness with TSynDictionary (in Add and Find) when I use mormot.crypt.core and it activates AES-NI.
for I := 0 to High(A) do
A[I] := IntToStr(I);
Dic := TSynDictionary.Create(TypeInfo(TStringDynArray), TypeInfo(TInt64DynArray));
T := GetTickCount64();
for I := 0 to High(A) do
Dic.Add(A[I], I);
WriteLn('Fill: ', GetTickCount64() - T);
T := GetTickCount64();
for I := 1 to High(A) do
Dic.Find(A[I]);
WriteLn('Find: ', GetTickCount64() - T);
Dic.Free; Here is the output of the mormot test:
- crc32c: 320,100 assertions passed 69.16ms
pas 430.8 MB/s fast 2 GB/s sse42 8.6 GB/s sse42+aesni 9.7 GB/sTested on Windows, latest mORMot and FPC on two machines with i3 and i9.
mormot.db.raw.sqlite3 has no initialization.
mormot.db.raw.sqlite3.static has one, at it creates TSqlite3LibraryStatic. In the Create, it calls ForceToUseSharedMemoryManager and I did disable it as a test an no changes.
Am I checking a wrong place?
I like to have this for memory tables too, as it helps to monitor my cache.
May it be something in the amalgamation?
I thought that is not a huge code as rules stated.
If you mean ForceToUseSharedMemoryManager, I tried disabling that too, but no change.
I like to get status of the DB to have a monitor on the DB, that was one of the reasons I've ported many of these functions previously for the sqlite3 units.
Hi,
I have a problem with SQLite memory status. I am trying to get the DB memory usage, but it will be always zero.
Do you have any idea why?
Also zero even with memory DB.
status64 results non-zero value for SQLITE_STATUS_PAGECACHE_OVERFLOW flag.
var
DB: TSqlDataBase;
Req: TSqlRequest;
Current, HighWater: Int64;
I: Integer;
begin
DB := TSqlDataBase.Create('test.db');
sqlite3.config(SQLITE_CONFIG_MEMSTATUS, Integer(True));
WriteLn('VersionNumber: ', sqlite3.VersionNumber);
DB.TransactionBegin;
DB.Execute('CREATE TABLE IF NOT EXISTS "Test" ("ID" INTEGER NOT NULL PRIMARY KEY, "Value" INTEGER);');
Req.Prepare(DB.DB, 'INSERT INTO "Test"("Value") VALUES(?);');
with Req do
for I := 1 to 10000 do
begin
Bind(1, I);
Step;
Reset;
end;
Req.Close;
DB.Commit;
WriteLn('RecordCount: ', DB.ExecuteNoExceptionInt64('SELECT COUNT(*) FROM Test;'));
Current := 0;
HighWater := 0;
WriteLn('status64: ', sqlite3.status64(SQLITE_STATUS_MEMORY_USED, @Current, @HighWater, Integer(False)));
WriteLn('Current: ', Current);
WriteLn('HighWater: ', HighWater);
WriteLn('memory_used: ', sqlite3.memory_used);
WriteLn('memory_highwater: ', sqlite3.memory_highwater(Integer(False)));
DB.Free;
end. Limiting prevents sudden issues. As for solution, I checked the result for 3M or 1000 bytes and load it after save, it worked correctly. I used this code for months and no problem and passed the checks until I faced this number.
Another question is why JSOn writer has a problem? I did use an external writer with owned file stream and still problem happens in Base64.
Thanks for the check but it seems not a size problem. As I stated before it had no problem with 1000 byte or 3 million item. Smaller and bigger is fine, the problem is around the 2.5M of 800 bytes.
It will happen again on:
- Set CompressAlgo to nil
- Saving to JSON
- Using random value for V
I faced this problem in a project with real values with the same exact behavior.
To be clear, I tried any combination of the above in such code and also in the context of my project with real values:
begin
D := TSynDictionary.Create(TypeInfo(TIntegerDynArray), TypeInfo(TValueDynArray));
D.CompressAlgo := nil;
for I := 1 to 2319851 do
begin
TAesPrng.Main.FillRandom(@V, SizeOf(V));
D.Add(I, V);
end;
D.SaveToJson;
WriteLn('Done');
ReadLn;
end. I faced a weird issue with TSynDictionary.
On a specific Value size and a specific count, it will crash (in SynLZ) when I want to save the content.
If I change the size of TValue to 1000 or count to 30M, it works fine.
The error seems related to buffer size as even if I save to JSON, it will happen again in Base64 instead of SynLZ.
Tried it with Lazarus 64bit (Trunk and Fixes) on Windows10 and mORMot 1 & 2.
program project1;
uses
mormot.core.base,
mormot.core.json;
type
TValue = record
T: array[1..800] of Byte;
end;
TValueDynArray = array of TValue;
var
D: TSynDictionary;
I: Integer;
V: TValue;
begin
D := TSynDictionary.Create(TypeInfo(TIntegerDynArray), TypeInfo(TValueDynArray));
for I := 1 to 2500000 do
D.Add(I, V);
D.SaveToBinary;
WriteLn('Done');
ReadLn;
end. I answered.
Leslie7, that is an interesting extension. First it needs to be added to the build by ab like other ones.
Done, please check.
Yes it is.
threadsafe is removed. Is there a reason as you did not remove it from TSqlite3Library?
I will rearrange and cleanup methods.
I saw your fix, why changing PUtf8Char made the problem?
Thanks for the new build, I checked it and now all methods can compile except progress_handler. More info: https://www.sqlite.org/capi3ref.html#sq … ss_handler
Shall I make a pull request on uncommenting deactivated methods in TSqlite3LibraryStatic.Create or you will?
Thanks ab.
Please let me know when the needed flags are added so we can uncomment deactivated methods and maybe rearrange them in "SQLite natural order". Also some cleanups maybe, see "Notes" on the changelog for more info.
Leslie7, that is an interesting extension. First it needs to be added to the build by ab like other ones.
Done, please check.
I've updated the sqlite3 units and added almost all the remaining methods from the API that seems useful.
There are 280 SQLite methods in the API, and we now have 171 (previously 91). Only VFS methods are remaining for now, other ones have a reason to not be included.
Not included ones:
These are the one that are not added and the reason. I will add any of them if you like.
- All the _16 methods as I do not see any use for them (many SQLite functions like sqlite3_bind_parameter_name return UTF8 anyway). The only one already existing is column_text16.
- Most of *64 methods like malloc64, status64, blob64 and text64. I do not see much use for them right now but SQLite says they are preferred.
- Legacy or deprecated methods like sqlite3_get_table
- Some _vX methods that has a more complete one already like sqlite3_trace
- Prohibited methods like sqlite3_os_end
- Deprecated flags like SQLITE_PREPARE_NORMALIZE
- Methods that already have a more complete option (eg sqlite3_result_error_nomem has sqlite3_result_error)
- Systemic methods like sleep or randomness as we have them already in Pascal code.
- String methods as we have them as or more powerful already in Pascal and mORMot like Format (eg sqlite3_stricmp) or can be achieved with a simple query (eg sqlite3_strlike).
- sqlite3_str_append
- sqlite3_str_appendall
- sqlite3_str_appendchar
- sqlite3_str_appendf
- sqlite3_str_errcode
- sqlite3_str_finish
- sqlite3_str_length
- sqlite3_str_new
- sqlite3_str_reset
- sqlite3_str_value
- sqlite3_str_vappendf
- sqlite3_stricmp
- sqlite3_strlike
- sqlite3_strnicmp
- sqlite3_vmprintf
- sqlite3_vsnprintf
- sqlite3_mprintf
- sqlite3_snprintf
- sqlite3_strglob
- Mutex methods as we have more powerful options already in Pascal and mORMot.
- sqlite3_mutex_alloc
- sqlite3_mutex_enter
- sqlite3_mutex_free
- sqlite3_mutex_held
- sqlite3_mutex_leave
- sqlite3_mutex_notheld
- sqlite3_mutex_try
- sqlite3_db_mutex
Todos:
- If you need or like to have some of the "Not included ones".
- Session and RBU and maybe more extension are good to add, but it is better to have them in the build beforehand so we can test and verify. Also maybe a structure to add extensions is a good idea as SQLite has many good options that can be useful.
- https://www.sqlite.org/rbu.html
- https://sqlite.org/sessionintro.html
- Missing VFS methods. I did not know how to check or use them.
- sqlite3_vfs_find
- sqlite3_vfs_register
- sqlite3_vfs_unregister
- sqlite3_free_filename
- sqlite3_filename_database
- sqlite3_filename_journal
- sqlite3_filename_wal
- sqlite3_win32_set_directory
- sqlite3_win32_set_directory16
- sqlite3_win32_set_directory8
- sqlite3_uri_boolean
- sqlite3_uri_int64
- sqlite3_uri_key
- sqlite3_uri_parameter
- sqlite3_file_control
- sqlite3_create_filename
- sqlite3_database_file_object
Notes:
- sqlite3_status64 is added and it seems there is no need for memory_used and memory_highwater anymore.
- I did not change the order of methods, but it may be a good idea to sort them better to match SQLite. Let me know if you like that.
- prepare_v3 is added, maybe it is a good idea to remove the v2, as v3 does the extract same thing more option.
- libversion_number is added so it is a good idea to change the Create method.
- extended_result_codes and Extended Result Code are added, maybe you like to enable it by default and use it in mORMot.
- create_collation_v2 is added, maybe it is a good idea to remove the v1, as v2 does the extact same thing with an optional destroy.
Finally these are the flags needed to be added to the build. All the missing methods are commented in TSqlite3LibraryStatic.Create, need to uncomment after adding.
- YYTRACKMAXSTACKDEPTH for SQLITE_STATUS_PARSER_STACK
- SQLITE_ENABLE_COLUMN_METADATA for column_database_name, column_table_name and
- column_origin_name
- SQLITE_ENABLE_STMT_SCANSTATUS for stmt_scanstatus and stmt_scanstatus_reset
- SQLITE_ENABLE_PREUPDATE_HOOK for sqlite3_preupdate_*_
- SQLITE_DBCONFIG_ENABLE_LOAD_EXTENSION for sqlite3_*_extension
- SQLITE_ENABLE_SNAPSHOT for sqlite3_snapshot*
- SQLITE_ENABLE_UNLOCK_NOTIFY for sqlite3_unlock_notify
- sqlite3_progress_handler is missed from the build
I would like to know your comments on the Todos and Notes.
And thank you for the clean structure, I tried to follow that and checked most of them.
Here is the result patches: https://gist.github.com/OkobaPatino/23e … 86003a094b
I will fix the PUtf8Char cases and add more of the API and send you the patch.
One question, some defined function in the static unit returning PAnsiChar, but you used PUtf8Char most of the time. Is there a particular reason?
As a test, I've added and checked these:
sqlite3_stmt_busy
sqlite3_stmt_isexplain
sqlite3_sql
sqlite3_expanded_sql
sqlite3_normalized_sql
Although your provided build has not sqlite3_normalized_sql. Can you add it?
I like to add more like scanstatus* next.
Here is the result patches: https://gist.github.com/OkobaPatino/76e … aa741255e9