New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Return data pointer in DBreezeObjectInsertResult after call ObjectInsert method #46

Closed
vladimir-shurakov opened this Issue May 25, 2018 · 7 comments

Comments

Projects
None yet
2 participants
@vladimir-shurakov

vladimir-shurakov commented May 25, 2018

Hi guys,

Is it possible to return direct pointer to inserted data when ObjectInsert method is used? We need to store this pointer in another table to perform synchronization operations. An example is given below:

public void InsertOrUpdateObject<TEntity>(List<TEntity> entityList)
{
string tableName = typeof(TEntity).Name.ToLower();
string syncTableName = tableName + "sync";

using (Transaction tran = _engine.GetTransaction())
{
    tran.SynchronizeTables(tableName, syncTableName);
    foreach (var entity in entityList)
    {
        var id = tran.ObjectGetNewIdentity<long>(tableName);
        List<DBreezeIndex> indexes = GetIndexedByIndicies(entity);

        var newObject = new DBreezeObject<TEntity>
        {
            Indexes = indexes,
            Entity = entity
        };
        DBreezeObjectInsertResult<TEntity> res = tran.ObjectInsert(tableName, newObject);
        //it will be good to have data pointer in DBreezeObjectInsertResult
        tran.Insert<byte[], byte[]>(syncTableName, 1.ToIndex(_synchronizationManager.SyncTransactionId, id), res.DataPointer);
    }
    tran.Commit();
}

}

Regards

@hhblaze

This comment has been minimized.

Owner

hhblaze commented May 25, 2018

Hi, unless you setup
tran.ObjectInsert(tableName, newObject, speedUpdate=true);
it is possible that even changed entity will reside the same disk space (if its size will be less or equal to the previous entity version size).
So, this logic can break your sync.

But if you setup speedUpdate to true (that is actually good not for each situation) you will get higher disk space consumption.

I would suggest to change sync event tracing logic.

Serialized objects can be compared on the byte[] level using extension function from DBreeze.Utils
var theyAreEqual = byte[] {2,3,4}._ByteArrayEquals(new byte[]{2,3,5});

hhblaze added a commit that referenced this issue May 25, 2018

@hhblaze

This comment has been minimized.

Owner

hhblaze commented May 25, 2018

Version 1.91 solves it and DBreezeObjectInsertResult has now PtrToObject,
also DBreezeObjectInsertResult has EntityWasInserted, so the code could look like

 DBreezeObjectInsertResult<TEntity> res = tran.ObjectInsert(tableName, newObject);
      
if(res.EntityWasInserted )
        tran.Insert<byte[], byte[]>(syncTableName, 1.ToIndex(_synchronizationManager.SyncTransactionId, id), res.PtrToObject);

Hopefully, it can be retrieved by tran.ObjectGetByFixedAddress

@vladimir-shurakov

This comment has been minimized.

vladimir-shurakov commented May 25, 2018

Thanks for quick response and suggestion!

Could you please shed the light on following situation (see code below):
class Entity()
{
int Id {get;set;}
string Name {get; set;}
}
//#1 step
var newEntity = new Entity() {Id = 1, Name = "New Entity"};
var newEntityRes = tran.ObjectInsert(tableName, new DBreezeObject<Entity>{ Entity = newEntity }, true);
var newEntityPtr = newEntityRes.PtrToObject;

//#2 step
var smallerEntity = new Entity() {Id = 1, Name = "Entity"};
var smallerEntityRes = tran.ObjectInsert(tableName, new DBreezeObject<Entity>{ Entity = smallerEntity}, false);
var smallerEntityPtr = smallerEntityRes.PtrToObject;

//#3 step
var biggerEntity = new Entity() {Id = 1, Name = "Bigger Entity"};
var biggerEntityRes = tran.ObjectInsert(tableName, new DBreezeObject<Entity>{ Entity = biggerEntity}, false);
var biggerEntityPtr = biggerEntityRes.PtrToObject;

//#4 step
var row = tran.SelectDirect<int, byte[]>("t1", newEntityPtr);
var exists = row.Exists;

My questions is:
1)
newEntityPtr == smallerEntityPtr (always)
newEntityPtr == biggerEntityPtr (if there are no Entities with with Id>1)
newEntityPtr != biggerEntityPtr otherwise

what value of exists variable in step 4:
my answer is:

true - if there are no Entities with with Id>1
false - otherwise

Regards!

@hhblaze

This comment has been minimized.

Owner

hhblaze commented May 25, 2018

First of all, in the newest NuGet release 1.91 renamed PtrToEntity->PtrToObject.

//Inserting new entity
            using (var tran = engine.GetTransaction())
            {
                var x1 = tran.ObjectInsert<byte[]>("t1", new DBreeze.Objects.DBreezeObject<byte[]>()
                {
                    Entity = new byte[] { 1, 2, 3 },
                    //NewEntity = true, //this is another speed optimzation flag, can be skipped until is really necessary
                    Indexes = new List<DBreeze.Objects.DBreezeIndex>()
                       {
                            new DBreeze.Objects.DBreezeIndex(1, (long)1){ PrimaryIndex = true }
                       }
                }, false); //inserting entity

                tran.Commit();

            }

            //Testing updates
            using (var tran = engine.GetTransaction())
            {


                var x1 = tran.ObjectInsert<byte[]>("t1", new DBreeze.Objects.DBreezeObject<byte[]>()
                {
                    Entity = new byte[] { 1, 2, 3 },                    
                    Indexes = new List<DBreeze.Objects.DBreezeIndex>()
                       {
                            new DBreeze.Objects.DBreezeIndex(1, (long)1){ PrimaryIndex = true }
                       }
                }, false);  //Speed insert is off, the equal entity on the level of byte[] will not be overwritten

                //--> will be false
                Console.Write(x1.EntityWasInserted);
                

                x1 = tran.ObjectInsert<byte[]>("t1", new DBreeze.Objects.DBreezeObject<byte[]>()
                {
                    Entity = new byte[] { 1, 2, 3 },
                    Indexes = new List<DBreeze.Objects.DBreezeIndex>()
                       {
                            new DBreeze.Objects.DBreezeIndex(1, (long)1){ PrimaryIndex = true }
                       }
                }, true); //Speed insert is on - entity will be overwritten (new PtToObject will be generated)

                //--> will be true
                Console.Write(x1.EntityWasInserted);


                x1 = tran.ObjectInsert<byte[]>("t1", new DBreeze.Objects.DBreezeObject<byte[]>()
                {
                    Entity = new byte[] { 1, 2, 3, 4 },
                    Indexes = new List<DBreeze.Objects.DBreezeIndex>()
                       {
                            new DBreeze.Objects.DBreezeIndex(1, (long)1){ PrimaryIndex = true }
                       }
                }, false);  //Speed insert is off

                //--> will be true because entity has changed
                Console.Write(x1.EntityWasInserted);

                tran.Commit();

            }
@hhblaze

This comment has been minimized.

Owner

hhblaze commented May 25, 2018

To get inserted value:

 //Inserting
            byte[] ptr1 = null;
            byte[] ptr2 = null;

            using (var tran = engine.GetTransaction())
            {
                var x1 = tran.ObjectInsert<byte[]>("t1", new DBreeze.Objects.DBreezeObject<byte[]>()
                {
                    Entity = new byte[] { 1, 2, 3 },
                    NewEntity = true,
                    Indexes = new List<DBreeze.Objects.DBreezeIndex>()
                       {
                            new DBreeze.Objects.DBreezeIndex(1, (long)1){ PrimaryIndex = true }
                       }
                });

                ptr1 = x1.PtrToObject;

                x1 = tran.ObjectInsert<byte[]>("t1", new DBreeze.Objects.DBreezeObject<byte[]>()
                {
                    Entity = new byte[] { 2, 6, 3 },
                    NewEntity = true,
                    Indexes = new List<DBreeze.Objects.DBreezeIndex>()
                       {
                            new DBreeze.Objects.DBreezeIndex(1, (long)2){ PrimaryIndex = true }
                       }
                });

                ptr2 = x1.PtrToObject;

                tran.Commit();
            }

            //Getting
            using (var tran = engine.GetTransaction())
            {
                //Variant 1 via index
                var exp = tran.Select<byte[], byte[]>("t1", 1.ToIndex((long)1))
                   .ObjectGet<byte[]>();

                //via pointer
                var do1 = tran.ObjectGetByFixedAddress<byte[]>("t1", ptr1);
                Console.WriteLine(do1.Entity.ToBytesString());

                do1 = tran.ObjectGetByFixedAddress<byte[]>("t1", ptr2);
                Console.WriteLine(do1.Entity.ToBytesString());
            }
@hhblaze

This comment has been minimized.

Owner

hhblaze commented May 25, 2018

SelectDirect

byte[] ptr1 = null;

            using (var tran = engine.GetTransaction())
            {
                tran.Insert<int, int>("t2", 1, 1, out ptr1);
                tran.Commit();
            }

            using (var tran = engine.GetTransaction())
            {
                var row = tran.SelectDirect<int, int>("t2", ptr1);
                Console.WriteLine(row.Exists); //->true

                //row = tran.SelectDirect<int, int>("t2", new byte[] { 5,6,7}); //error non-existing

                row = tran.SelectDirect<int, int>("t2", null); //ok
                Console.WriteLine(row.Exists); //->false
            }
@vladimir-shurakov

This comment has been minimized.

vladimir-shurakov commented May 25, 2018

PtrToEntity->PtrToObject renamed in my previous comment.
Thanks a lot for good examples.
It's time to close the issue.
Good luck.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment