Ejemplo n.º 1
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="WasUpdated">true means that value existed and was updated</param>
        /// <param name="dontUpdateIfExists">When true - if value exists, we dont update it. If WasUpdated = true then we value exists, if false - we have inserted new one</param>
        /// <returns></returns>
        public byte[] AddKey(ref byte[] key, ref byte[] value, out bool WasUpdated, bool dontUpdateIfExists)
        {
            //indicates that key we insert, already existed in the system and was updated
            WasUpdated = false;

            //if (key == null || key.Length == 0)
            //    return;
            if (key == null)
            {
                return(null);
            }

            if (key.Length > UInt16.MaxValue)
            {
                throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.KEY_IS_TOO_LONG);
            }



            LTrieGenerationNode gn = null;

            if (_generationMap.Count() == 0)
            {
                //Loading it from Link TO ZERO Pointer
                gn         = new LTrieGenerationNode(this);
                gn.Pointer = this.LinkToZeroNode;
                //gn.Value=0; - default
                _generationMap.Add(0, gn);

                gn.ReadSelf(false, null);
            }


            LTrieSetupKidResult res = new LTrieSetupKidResult();

            byte[] key1 = null; //we need it as null
            byte[] val1 = null;

            //len can be expanded inside of the algorithm maximum by one
            int len = key.Length;

            bool cleanCheck = true;



            /*Special case key is empty byte[0] */
            if (key.Length == 0)
            {
                //Saving byte[0] key
                res = _generationMap[0].SetupKidWithValue((byte)0, true, ref key, ref value, false, out WasUpdated, dontUpdateIfExists);

                return(res.ValueLink);
            }
            /**/


            for (int i = 0; i < len; i++)
            {
                //Getting kid from actual generation map

                if (cleanCheck && i != 0 && _generationMap.ContainsKey(i) && _generationMap[i].Value != key[i - 1])
                {
                    cleanCheck = false;

                    //In case if i>0, it's not the first element and we have to compare if there are generation mapsstarting from this point.
                    //If generationMap[i] exists and it's value not that what we want, we have to clean full in memory generation map as

                    //Save_node... up to i
                    Save_GM_nodes_Starting_From(i);

                    //Remove Gen Map starting from... i
                    _generationMap.RemoveBiggerOrEqualThenKey(i);
                }

                if (!_generationMap.ContainsKey(i))
                {
                    //All ok, for the first generation node

                    //We read or create generation map
                    //And add it to the _generationMap

                    gn         = new LTrieGenerationNode(this);
                    gn.Value   = key[i - 1];
                    gn.Pointer = _generationMap[i - 1].KidsInNode.GetPointerToTheKid(key[i - 1]);
                    //gn.Pointer = _generationMap[i - 1].GetKidPointer(key[i - 1]);

                    _generationMap.Add(i, gn);

                    if (gn.Pointer != null)
                    {
                        gn.ReadSelf(false, null);
                    }
                    else
                    {
                        gn.Pointer = new byte[DefaultPointerLen];       //!!!!!!!!!!!!! Check if it'S really necessary or we can leave it as null
                    }
                }


                //Generation Node in this trie can have link to kids [0-255] and link to the value.
                //If Kids>0 && Value Link is not Default Empty Pointer, then this value-link refers to the end of the sentence.
                //If Kids==0 && Value Link is not Default Empty Pointer, then this value-link refers to the sentence which can go after this last character, so also to the value.
                //Dual behaviour.


                if (res.KeyOldKid != null)
                {
                    //It means that on this stage probably we have to setup both kids
                    //We can check Length of both keys and their current condition

                    //key1 = res.KeyOldKid; //we need it as null
                    val1 = res.ValPtrOldKid;


                    if ((res.KeyOldKid.Length - 1) < i)
                    {
                        _generationMap[i].SetupKidWithValue((byte)0, true, ref key1, ref val1, true, out WasUpdated, dontUpdateIfExists);
                    }
                    else
                    {
                        _generationMap[i].SetupKidWithValue(res.KeyOldKid[i], false, ref key1, ref val1, true, out WasUpdated, dontUpdateIfExists);
                    }

                    //Cleaning up KeyOldKid - probably not necessary, de bene esse (just in case)
                    res.KeyOldKid = null;
                }


                //One more only then we setup value, otherwise we bind to the kid, Check Docs in fileDb LtrieSpreadExample1.jpg
                res = _generationMap[i].SetupKidWithValue(((i == key.Length) ? (byte)0 : key[i]), (i == key.Length), ref key, ref value, false, out WasUpdated, dontUpdateIfExists);

                if (!res.IterateFurther)
                {
                    //After setting up value, we can just exit
                    return(res.ValueLink);
                }
                else
                {
                    //we don't need value on this phase, we can go on further

                    //Expanding iteration cycle by one and, on the next iteration cycle we should go out from the loop.
                    if (i == (key.Length - 1))
                    {
                        len++;
                    }
                }
            }

            //Should not happen as null, we have to return link to the full value
            return(null);
        }

        /// <summary>
        /// Returns link to the full value together with the key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="startIndex"></param>
        /// <param name="WasUpdated">indicates that key we insert, already existed in the system and was updated</param>
        /// <returns></returns>
        public byte[] AddKeyPartially(ref byte[] key, ref byte[] value, uint startIndex, out long valueStartPtr, out bool WasUpdated)
        {
            WasUpdated = false;

            if (key == null)
            {
                valueStartPtr = -1;
                return(null);
            }

            if (key.Length > UInt16.MaxValue)
            {
                throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.KEY_IS_TOO_LONG);
            }

            if (value == null)
            {
                throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.PARTIAL_VALUE_CANT_BE_NULL);
            }


            LTrieGenerationNode gn = null;

            if (_generationMap.Count() == 0)
            {
                //Loading it from Link TO ZERO Pointer
                gn         = new LTrieGenerationNode(this);
                gn.Pointer = this.LinkToZeroNode;
                //gn.Value=0; - default
                _generationMap.Add(0, gn);

                gn.ReadSelf(false, null);
            }


            LTrieSetupKidResult res = new LTrieSetupKidResult();

            byte[] key1 = null; //we need it as null
            byte[] val1 = null;

            //len can be expanded inside of the algorithm maximum by one
            int len = key.Length;

            bool cleanCheck = true;

            /*Special case key is empty byte[0] */
            if (key.Length == 0)
            {
                //Saving byte[0] key
                res = _generationMap[0].SetupKidWithValuePartially((byte)0, true, ref key, ref value, false, startIndex, out valueStartPtr, out WasUpdated);

                return(res.ValueLink);
            }
            /**/

            for (int i = 0; i < len; i++)
            {
                //Getting kid from actual generation map

                if (cleanCheck && i != 0 && _generationMap.ContainsKey(i) && _generationMap[i].Value != key[i - 1])
                {
                    cleanCheck = false;

                    //In case if i>0, it's not the first element and we have to compare if there are generation mapsstarting from this point.
                    //If generationMap[i] exists and it's value not that what we want, we have to clean full in memory generation map as

                    //Save_node... up to i
                    Save_GM_nodes_Starting_From(i);

                    //Remove Gen Map starting from... i
                    _generationMap.RemoveBiggerOrEqualThenKey(i);
                }

                if (!_generationMap.ContainsKey(i))
                {
                    //All ok, for the first generation node

                    //We read or create generation map
                    //And add it to the _generationMap

                    gn         = new LTrieGenerationNode(this);
                    gn.Value   = key[i - 1];
                    gn.Pointer = _generationMap[i - 1].KidsInNode.GetPointerToTheKid(key[i - 1]);
                    //gn.Pointer = _generationMap[i - 1].GetKidPointer(key[i - 1]);

                    _generationMap.Add(i, gn);

                    if (gn.Pointer != null)
                    {
                        gn.ReadSelf(false, null);
                    }
                    else
                    {
                        gn.Pointer = new byte[DefaultPointerLen];       //!!!!!!!!!!!!! Check if it'S really necessary or we can leave it as null
                    }
                }


                //Generation Node in this trie can have link to kids [0-255] and link to the value.
                //If Kids>0 && Value Link is not Default Empty Pointer, then this value-link refers to the end of the sentence.
                //If Kids==0 && Value Link is not Default Empty Pointer, then this value-link refers to the sentence which can go after this last character, so also to the value.
                //Dual behaviour.


                if (res.KeyOldKid != null)
                {
                    //It means that on this stage probably we have to setup both kids
                    //We can check Length of both keys and their current condition

                    //key1 = res.KeyOldKid; //we need it as null
                    val1 = res.ValPtrOldKid;


                    if ((res.KeyOldKid.Length - 1) < i)
                    {
                        _generationMap[i].SetupKidWithValuePartially((byte)0, true, ref key1, ref val1, true, startIndex, out valueStartPtr, out WasUpdated);
                    }
                    else
                    {
                        _generationMap[i].SetupKidWithValuePartially(res.KeyOldKid[i], false, ref key1, ref val1, true, startIndex, out valueStartPtr, out WasUpdated);
                    }

                    //Cleaning up KeyOldKid - probably not necessary, de bene esse (just in case)
                    res.KeyOldKid = null;
                }


                //One more only then we setup value, otherwise we bind to the kid, Check Docs in fileDb LtrieSpreadExample1.jpg
                res = _generationMap[i].SetupKidWithValuePartially(((i == key.Length) ? (byte)0 : key[i]), (i == key.Length), ref key, ref value, false, startIndex, out valueStartPtr, out WasUpdated);

                if (!res.IterateFurther)
                {
                    //After setting up value, we can just exit
                    return(res.ValueLink);
                }
                else
                {
                    //we don't need value on this phase, we can go on further

                    //Expanding iteration cycle by one and, on the next iteration cycle we should go out from the loop.
                    if (i == (key.Length - 1))
                    {
                        len++;
                    }
                }
            }

            //Should not happen as null, we have to return link to the full value
            valueStartPtr = -1;
            return(null);
        }

        /// <summary>
        /// Check TransactionCommit in case of RemoveAll with file Recreation.
        /// Note if some other threads are reading parallel data, exception will be thrown in their transaction.
        /// It's correct.
        /// </summary>
        /// <param name="withFileRecreation"></param>
        public void RemoveAll(bool withFileRecreation)
        {
            if (!withFileRecreation)
            {
                LTrieGenerationNode gn = null;

                _generationMap.Clear();

                if (_generationMap.Count() == 0)
                {
                    //Loading it from Link TO ZERO Pointer
                    gn         = new LTrieGenerationNode(this);
                    gn.Pointer = this.LinkToZeroNode;
                    //gn.Value=0; - default
                    _generationMap.Add(0, gn);

                    gn.ReadSelf(false, null);
                }


                _generationMap[0].RemoveAllKids();
            }
            else
            {
                try
                {
                    this.Tree.Cache.RecreateDB();

                    //Important, Better to re-read all generation nodes for safety reasons, de bene esse
                    this._generationMap.Clear();

                    //And re-Read RootNode
                    ReadRootNode();
                }
                catch (Exception ex)
                {
                    ////////////////////  MADE THAT Table is not Opearable on the upper level,
                    throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.RECREATE_TABLE_FAILED, this.Tree.TableName, ex);
                }
            }
        }

        /// <summary>
        /// Takes value fresh no committed value row.GetFullValue(false);
        /// </summary>
        /// <param name="oldKey"></param>
        /// <param name="newKey"></param>
        /// <returns></returns>
        public bool ChangeKey(ref byte[] oldKey, ref byte[] newKey)
        {
            byte[] refToInsertedValue = null;
            return(this.ChangeKey(ref oldKey, ref newKey, out refToInsertedValue));
        }

        /// <summary>
        /// Takes value fresh no committed value row.GetFullValue(false);
        /// </summary>
        /// <param name="oldKey"></param>
        /// <param name="newKey"></param>
        /// <param name="refToInsertedValue">returns ptr in the file to the new key</param>
        /// <returns></returns>
        public bool ChangeKey(ref byte[] oldKey, ref byte[] newKey, out byte[] refToInsertedValue)
        {
            //The best way read old, remove, and create new, with holding of transactions,
            //just changing pointers to the value will give nothing, because in the value also the full key is written, so we will need
            //to make new value
            refToInsertedValue = null;

            var row = this.GetKey(oldKey, false);

            if (row.Exists)
            {
                byte[] oldKeyValue  = row.GetFullValue(false);
                bool   WasRemoved   = false;
                byte[] deletedValue = null;
                this.RemoveKey(ref oldKey, out WasRemoved, false, out deletedValue);
                bool WasUpdated = false;
                refToInsertedValue = this.AddKey(ref newKey, ref oldKeyValue, out WasUpdated, false);

                refToInsertedValue = refToInsertedValue.EnlargeByteArray_BigEndian(8);

                return(true);
            }
            return(false);
        }

        /// <summary>
        /// Will return pointer to the value of the removing kid (if it existed). Otherwise NULL.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="WasRemoved">indicates that value existed if true</param>
        /// <param name="retrieveDeletedValue">indicates if we should bind deleted value to the result</param>
        /// <param name="deletedValue">interesting only if WasRemoved = true and retrieveDeletedValue is true</param>
        /// <returns></returns>
        public void RemoveKey(ref byte[] key, out bool WasRemoved, bool retrieveDeletedValue, out byte[] deletedValue)
        {
            WasRemoved   = false;
            deletedValue = null;
            //if (key == null || key.Length == 0)
            //    return;

            if (key == null)
            {
                return;
            }

            if (key.Length > UInt16.MaxValue)
            {
                throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.KEY_IS_TOO_LONG);
            }


            LTrieGenerationNode gn = null;

            if (_generationMap.Count() == 0)
            {
                //Loading it from Link TO ZERO Pointer
                gn         = new LTrieGenerationNode(this);
                gn.Pointer = this.LinkToZeroNode;
                //gn.Value=0; - default
                _generationMap.Add(0, gn);

                gn.ReadSelf(false, null);
            }


            LTrieSetupKidResult res = new LTrieSetupKidResult();

            //byte[] key1 = null; //we need it as null
            //byte[] val1 = null;

            //len can be expanded inside of the algorithm maximum by one
            int len = key.Length;

            bool cleanCheck = true;

            bool iterateFurther = false;

            /*SPECIAL CASE key=byte[0]*/
            if (key.Length == 0)
            {
                _generationMap[0].RemoveKid((byte)0, true, ref key, out WasRemoved, retrieveDeletedValue, out deletedValue);

                return;
            }
            /***************************/

            for (int i = 0; i < len; i++)
            {
                //Getting kid from actual generation map

                if (cleanCheck && i != 0 && _generationMap.ContainsKey(i) && _generationMap[i].Value != key[i - 1])
                {
                    cleanCheck = false;

                    //In case if i>0, it's not the first element and we have to compare if there are generation mapsstarting from this point.
                    //If generationMap[i] exists and it's value not that what we want, we have to clean full in memory generation map as

                    //Save_node... up to i
                    Save_GM_nodes_Starting_From(i);

                    //Remove Gen Map starting from... i
                    _generationMap.RemoveBiggerOrEqualThenKey(i);
                }

                if (!_generationMap.ContainsKey(i))
                {
                    //All ok, for the first generation node

                    //We read or create generation map
                    //And add it to the _generationMap

                    gn         = new LTrieGenerationNode(this);
                    gn.Value   = key[i - 1];
                    gn.Pointer = _generationMap[i - 1].KidsInNode.GetPointerToTheKid(key[i - 1]);
                    //gn.Pointer = _generationMap[i - 1].GetKidPointer(key[i - 1]);

                    _generationMap.Add(i, gn);

                    if (gn.Pointer != null)
                    {
                        gn.ReadSelf(false, null);
                    }
                    else
                    {
                        gn.Pointer = new byte[DefaultPointerLen];       //!!!!!!!!!!!!! Check if it'S really necessary or we can leave it as null
                    }
                }

                //Trying to remove as a result we receive information if we should iterate further
                iterateFurther = _generationMap[i].RemoveKid((i == key.Length) ? (byte)0 : key[i], (i == key.Length), ref key, out WasRemoved, retrieveDeletedValue, out deletedValue);

                if (!iterateFurther)
                {
                    break;
                }
                else
                {
                    if (i == (key.Length - 1))
                    {
                        len++;
                    }
                }
            }
        }
Ejemplo n.º 2
0
        public LTrieSetupKidResult SetupKidWithValuePartially(byte kid, bool lastElementOfTheKey, ref byte[] fullKey, ref byte[] value, bool useExistingPointerToValue, uint startIndex, out long valueStartPtr, out bool WasUpdated)
        {
            //useExistingPointerToValue is used to move previously saved kid to the new place
            ToWrite = true;
            WasUpdated = false;

            LTrieSetupKidResult res = new LTrieSetupKidResult();

            byte[] ptr = null;
            LTrieKid lKid = null;

            bool tryToOverWrite = true;

            if (lastElementOfTheKey)
            {
                //We must setup Kid value
                if (!useExistingPointerToValue)     //Hack for oldKid link replacement
                {
                    //Here we also can decide if kid existed, probably we could overwrite it (in total 3 places also in the bottom)
                    lKid = KidsInNode.GetKidValue();

                    if (!lKid.Exists)
                    {
                        tryToOverWrite = false;
                        this._root.RecordsCount++;
                    }

                    WasUpdated = tryToOverWrite;
                    ptr = this.WriteKidValuePartially(ref fullKey, ref value, tryToOverWrite, lKid.Ptr, startIndex, out valueStartPtr);
                }
                else
                {
                    valueStartPtr = -1;
                    ptr = value;
                }

                KidsInNode.AddKid(256, ptr);
                res.ValueLink = ptr;
                res.IterateFurther = false;
                return res;
            }
            else
            {

                if (KidsInNode.ContainsKid(kid))
                {
                    //When we Setup Old Kid we should never come here

                    lKid = KidsInNode.GetKid(kid);

                    if (!lKid.LinkToNode)
                    {
                        //Here we have link to the value

                        //We will check here if it's the same key

                        ptr = this._root.Tree.Cache.ReadKey(false, lKid.Ptr);

                        if (fullKey._ByteArrayEquals(ptr))
                        {
                            //Insert key equals to storedKey, it means - UPDATE

                            //We write for now always on the new place value and update reference
                            WasUpdated = true;
                            ptr = this.WriteKidValuePartially(ref fullKey, ref value, true, lKid.Ptr, startIndex, out valueStartPtr);

                            KidsInNode.AddKid(kid, ptr);
                            res.ValueLink = ptr;
                            res.IterateFurther = false;
                            return res;
                        }
                        else
                        {
                            //Remembering old Key
                            res.KeyOldKid = ptr;
                            //Remembering old link
                            res.ValPtrOldKid = KidsInNode.ReplaceValueLinkOnKidLink(kid);
                        }

                    }

                    valueStartPtr = -1;
                    res.IterateFurther = true;
                    return res;
                }
                else
                {
                    //Just save this one
                    if (!useExistingPointerToValue)
                    {
                        //Here we also can decide if kid existed, probably we could overwrite it (2 places also check up there)
                        lKid = KidsInNode.GetKid(kid);

                        if (!lKid.Exists)
                        {
                            tryToOverWrite = false;
                            this._root.RecordsCount++;
                        }

                        WasUpdated = tryToOverWrite;
                        ptr = this.WriteKidValuePartially(ref fullKey, ref value, tryToOverWrite, lKid.Ptr, startIndex, out valueStartPtr);
                    }
                    else
                    {
                        valueStartPtr = -1;
                        ptr = value;       //Hack for oldKid link replacement
                    }

                    KidsInNode.AddKid(kid, ptr);
                    res.ValueLink = ptr;
                    res.IterateFurther = false;
                    return res;
                }
            }
        }
Ejemplo n.º 3
0
        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="WasUpdated">true means that value existed and was updated</param>
        /// <param name="dontUpdateIfExists">When true - if value exists, we dont update it. If WasUpdated = true then we value exists, if false - we have inserted new one</param>
        /// <returns></returns>
        public byte[] AddKey(ref byte[] key, ref byte[] value, out bool WasUpdated, bool dontUpdateIfExists)
        {
            //indicates that key we insert, already existed in the system and was updated
            WasUpdated = false;

            //if (key == null || key.Length == 0)
            //    return;
            if (key == null)
                return null;

            if (key.Length > UInt16.MaxValue)
                throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.KEY_IS_TOO_LONG);

            LTrieGenerationNode gn = null;

            if (_generationMap.Count() == 0)
            {
                //Loading it from Link TO ZERO Pointer
                gn = new LTrieGenerationNode(this);
                gn.Pointer = this.LinkToZeroNode;
                //gn.Value=0; - default
                _generationMap.Add(0, gn);

                gn.ReadSelf(false, null);
            }

            LTrieSetupKidResult res = new LTrieSetupKidResult();

            byte[] key1 = null; //we need it as null
            byte[] val1 = null;

            //len can be expanded inside of the algorithm maximum by one
            int len = key.Length;

            bool cleanCheck = true;

            /*Special case key is empty byte[0] */
            if (key.Length == 0)
            {
                //Saving byte[0] key
                res = _generationMap[0].SetupKidWithValue((byte)0, true, ref key, ref value, false, out WasUpdated, dontUpdateIfExists);

                return res.ValueLink;
            }
            /**/

            for (int i = 0; i < len; i++)
            {
                //Getting kid from actual generation map

                if (cleanCheck && i != 0 && _generationMap.ContainsKey(i) && _generationMap[i].Value != key[i - 1])
                {
                    cleanCheck = false;

                    //In case if i>0, it's not the first element and we have to compare if there are generation mapsstarting from this point.
                    //If generationMap[i] exists and it's value not that what we want, we have to clean full in memory generation map as

                    //Save_node... up to i
                    Save_GM_nodes_Starting_From(i);

                    //Remove Gen Map starting from... i
                    _generationMap.RemoveBiggerOrEqualThenKey(i);
                }

                if (!_generationMap.ContainsKey(i))
                {
                    //All ok, for the first generation node

                    //We read or create generation map
                    //And add it to the _generationMap

                    gn = new LTrieGenerationNode(this);
                    gn.Value = key[i - 1];
                    gn.Pointer = _generationMap[i - 1].KidsInNode.GetPointerToTheKid(key[i - 1]);
                    //gn.Pointer = _generationMap[i - 1].GetKidPointer(key[i - 1]);

                    _generationMap.Add(i, gn);

                    if (gn.Pointer != null)
                        gn.ReadSelf(false, null);
                    else
                        gn.Pointer = new byte[DefaultPointerLen];       //!!!!!!!!!!!!! Check if it'S really necessary or we can leave it as null
                }

                //Generation Node in this trie can have link to kids [0-255] and link to the value.
                //If Kids>0 && Value Link is not Default Empty Pointer, then this value-link refers to the end of the sentence.
                //If Kids==0 && Value Link is not Default Empty Pointer, then this value-link refers to the sentence which can go after this last character, so also to the value.
                //Dual behaviour.

                if (res.KeyOldKid != null)
                {
                    //It means that on this stage probably we have to setup both kids
                    //We can check Length of both keys and their current condition

                    //key1 = res.KeyOldKid; //we need it as null
                    val1 = res.ValPtrOldKid;

                    if ((res.KeyOldKid.Length - 1) < i)
                    {
                        _generationMap[i].SetupKidWithValue((byte)0, true, ref key1, ref val1, true, out WasUpdated, dontUpdateIfExists);
                    }
                    else
                    {
                        _generationMap[i].SetupKidWithValue(res.KeyOldKid[i], false, ref key1, ref val1, true, out WasUpdated, dontUpdateIfExists);
                    }

                    //Cleaning up KeyOldKid - probably not necessary, de bene esse (just in case)
                    res.KeyOldKid = null;
                }

                //One more only then we setup value, otherwise we bind to the kid, Check Docs in fileDb LtrieSpreadExample1.jpg
                res = _generationMap[i].SetupKidWithValue(((i == key.Length) ? (byte)0 : key[i]), (i == key.Length), ref key, ref value, false, out WasUpdated, dontUpdateIfExists);

                if (!res.IterateFurther)
                {
                    //After setting up value, we can just exit
                    return res.ValueLink;
                }
                else
                {
                    //we don't need value on this phase, we can go on further

                    //Expanding iteration cycle by one and, on the next iteration cycle we should go out from the loop.
                    if (i == (key.Length - 1))
                        len++;
                }

            }

            //Should not happen as null, we have to return link to the full value
            return null;
        }

        /// <summary>
        /// Returns link to the full value together with the key
        /// </summary>
        /// <param name="key"></param>
        /// <param name="value"></param>
        /// <param name="startIndex"></param>
        /// <param name="WasUpdated">indicates that key we insert, already existed in the system and was updated</param>
        /// <returns></returns>
        public byte[] AddKeyPartially(ref byte[] key, ref byte[] value, uint startIndex, out long valueStartPtr,out bool WasUpdated)
        {
            WasUpdated = false;

            if (key == null)
            {
                valueStartPtr = -1;
                return null;
            }

            if (key.Length > UInt16.MaxValue)
                throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.KEY_IS_TOO_LONG);

            if (value == null)
                throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.PARTIAL_VALUE_CANT_BE_NULL);

            LTrieGenerationNode gn = null;

            if (_generationMap.Count() == 0)
            {
                //Loading it from Link TO ZERO Pointer
                gn = new LTrieGenerationNode(this);
                gn.Pointer = this.LinkToZeroNode;
                //gn.Value=0; - default
                _generationMap.Add(0, gn);

                gn.ReadSelf(false, null);
            }

            LTrieSetupKidResult res = new LTrieSetupKidResult();

            byte[] key1 = null; //we need it as null
            byte[] val1 = null;

            //len can be expanded inside of the algorithm maximum by one
            int len = key.Length;

            bool cleanCheck = true;

            /*Special case key is empty byte[0] */
            if (key.Length == 0)
            {
                //Saving byte[0] key
                res = _generationMap[0].SetupKidWithValuePartially((byte)0, true, ref key, ref value, false, startIndex, out valueStartPtr, out WasUpdated);

                return res.ValueLink;
            }
            /**/

            for (int i = 0; i < len; i++)
            {
                //Getting kid from actual generation map

                if (cleanCheck && i != 0 && _generationMap.ContainsKey(i) && _generationMap[i].Value != key[i - 1])
                {
                    cleanCheck = false;

                    //In case if i>0, it's not the first element and we have to compare if there are generation mapsstarting from this point.
                    //If generationMap[i] exists and it's value not that what we want, we have to clean full in memory generation map as

                    //Save_node... up to i
                    Save_GM_nodes_Starting_From(i);

                    //Remove Gen Map starting from... i
                    _generationMap.RemoveBiggerOrEqualThenKey(i);
                }

                if (!_generationMap.ContainsKey(i))
                {
                    //All ok, for the first generation node

                    //We read or create generation map
                    //And add it to the _generationMap

                    gn = new LTrieGenerationNode(this);
                    gn.Value = key[i - 1];
                    gn.Pointer = _generationMap[i - 1].KidsInNode.GetPointerToTheKid(key[i - 1]);
                    //gn.Pointer = _generationMap[i - 1].GetKidPointer(key[i - 1]);

                    _generationMap.Add(i, gn);

                    if (gn.Pointer != null)
                        gn.ReadSelf(false, null);
                    else
                        gn.Pointer = new byte[DefaultPointerLen];       //!!!!!!!!!!!!! Check if it'S really necessary or we can leave it as null
                }

                //Generation Node in this trie can have link to kids [0-255] and link to the value.
                //If Kids>0 && Value Link is not Default Empty Pointer, then this value-link refers to the end of the sentence.
                //If Kids==0 && Value Link is not Default Empty Pointer, then this value-link refers to the sentence which can go after this last character, so also to the value.
                //Dual behaviour.

                if (res.KeyOldKid != null)
                {
                    //It means that on this stage probably we have to setup both kids
                    //We can check Length of both keys and their current condition

                    //key1 = res.KeyOldKid; //we need it as null
                    val1 = res.ValPtrOldKid;

                    if ((res.KeyOldKid.Length - 1) < i)
                    {
                        _generationMap[i].SetupKidWithValuePartially((byte)0, true, ref key1, ref val1, true, startIndex, out valueStartPtr, out WasUpdated);
                    }
                    else
                    {
                        _generationMap[i].SetupKidWithValuePartially(res.KeyOldKid[i], false, ref key1, ref val1, true, startIndex, out valueStartPtr, out WasUpdated);
                    }

                    //Cleaning up KeyOldKid - probably not necessary, de bene esse (just in case)
                    res.KeyOldKid = null;
                }

                //One more only then we setup value, otherwise we bind to the kid, Check Docs in fileDb LtrieSpreadExample1.jpg
                res = _generationMap[i].SetupKidWithValuePartially(((i == key.Length) ? (byte)0 : key[i]), (i == key.Length), ref key, ref value, false, startIndex, out valueStartPtr, out WasUpdated);

                if (!res.IterateFurther)
                {
                    //After setting up value, we can just exit
                    return res.ValueLink;
                }
                else
                {
                    //we don't need value on this phase, we can go on further

                    //Expanding iteration cycle by one and, on the next iteration cycle we should go out from the loop.
                    if (i == (key.Length - 1))
                        len++;
                }

            }

            //Should not happen as null, we have to return link to the full value
            valueStartPtr = -1;
            return null;
        }

        /// <summary>
        /// Takes value fresh no committed value row.GetFullValue(false);
        /// </summary>
        /// <param name="oldKey"></param>
        /// <param name="newKey"></param>
        /// <returns></returns>
        public bool ChangeKey(ref byte[] oldKey, ref byte[] newKey)
        {
            byte[] refToInsertedValue = null;
            return this.ChangeKey(ref oldKey, ref newKey, out refToInsertedValue);
        }

        /// <summary>
        /// Takes value fresh no committed value row.GetFullValue(false);
        /// </summary>
        /// <param name="oldKey"></param>
        /// <param name="newKey"></param>
        /// <param name="refToInsertedValue">returns ptr in the file to the new key</param>
        /// <returns></returns>
        public bool ChangeKey(ref byte[] oldKey, ref byte[] newKey, out byte[] refToInsertedValue)
        {
            //The best way read old, remove, and create new, with holding of transactions,
            //just changing pointers to the value will give nothing, because in the value also the full key is written, so we will need
            //to make new value
            refToInsertedValue = null;

            var row = this.GetKey(oldKey,false);

            if (row.Exists)
            {
                byte[] oldKeyValue = row.GetFullValue(false);
                bool WasRemoved = false;
                byte[] deletedValue = null;
                this.RemoveKey(ref oldKey, out WasRemoved, false, out deletedValue);
                bool WasUpdated = false;
                refToInsertedValue = this.AddKey(ref newKey, ref oldKeyValue,out WasUpdated,false);

                refToInsertedValue = refToInsertedValue.EnlargeByteArray_BigEndian(8);

                return true;
            }
            return false;
        }

        public void Commit()
        {
            try
            {

                this.Save_GM_nodes_Starting_From(0);

                byte[] oldRoot = me;

                me = this.SerializeRootNode();

                //Synchronized inside
                //DBreeze.Diagnostic.SpeedStatistic.StartCounter("Commit");
                //this.Tree.Cache.Commit(this.EmptyPointer, ref me, ref oldRoot);
                this.Tree.Cache.Commit(ref me, ref oldRoot);
                //DBreeze.Diagnostic.SpeedStatistic.StopCounter("Commit");

            }
            catch (Exception ex)
            {
                ////rollbak will be done on the level of the tree

                ////////////////////////////////////////
                throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.COMMIT_FAILED, this.Tree.TableName, ex);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="key"></param>
        /// <returns></returns>
        public LTrieRow GetKey(byte[] key, bool useCache)
        {
            //Later change TreeKVP (for RootNode Interface or smth like this) and make it unversal, this one must return value
            LTrieRow kv = new LTrieRow(this);

            kv.Key = key;

            //if (key == null || key.Length == 0)
            //    return kv;

            if (key == null)
                return kv;

            LTrieGenerationNode gn = null;

            if (_generationMap.Count() == 0)
            {
                //Loading it from Link TO ZERO Pointer
                gn = new LTrieGenerationNode(this);
                gn.Pointer = this.LinkToZeroNode;
                //gn.Value=0; - default
                _generationMap.Add(0, gn);

                gn.ReadSelf(useCache, _generationMap.GenerateMapNodesValuesUpToIndex(0));
                //gn.ReadSelf();
            }

            bool cleanCheck = true;

            LTrieKid kidDef = null;
            int p = 0;

            int len = key.Length;

            /*SPECIAL CASE key = byte[0]*/
            if (key.Length == 0)
            {
                kidDef = _generationMap[0].GetKidAsValue(true, 1);
                if (kidDef.Exists)
                {
                    kv.LinkToValue = kidDef.Ptr;
                }
                return kv;
            }
            /****************************/

            for (int i = 0; i < len; i++)
            {
                //Getting kid from actual generation map

                if (cleanCheck && i != 0 && _generationMap.ContainsKey(i) && _generationMap[i].Value != key[i - 1])
                {
                    cleanCheck = false;
                    _generationMap.RemoveBiggerOrEqualThenKey(i);
                }

                if (!_generationMap.ContainsKey(i))
                {
                    gn = new LTrieGenerationNode(this);
                    gn.Value = key[i - 1];
                    gn.Pointer = _generationMap[i - 1].KidsInNode.GetPointerToTheKid(key[i - 1]);

                    //FIND A SOLUTION FOR THIS NULL or EMPTY POINTER
                    //if (gn.Pointer == null || this._IfPointerIsEmpty(gn.Pointer))
                    //    return kv;
                    if (gn.Pointer == null || gn.Pointer._IfPointerIsEmpty(this.DefaultPointerLen))
                        return kv;

                    _generationMap.Add(i, gn);

                    gn.ReadSelf(useCache, _generationMap.GenerateMapNodesValuesUpToIndex(i));
                    //gn.ReadSelf();
                }

                //Also if last element then supply 256 to get value not the link to value (if no value exit)
                //If kid is a link to next node we iterate further, if link on the value, we retrieve full key and value as link for TreeKVP stoping iteration
                //If link is empty (no kid) we return empty

                if (i >= key.Length)
                    p = i - 1;
                else
                    p = i;

                kidDef = _generationMap[i].GetKidAsValue((i >= (key.Length)), key[p]);

                if (kidDef.Exists)
                {
                    if (kidDef.ValueKid)
                    {
                        kv.LinkToValue = kidDef.Ptr;
                        return kv;
                    }

                    if (!kidDef.LinkToNode)
                    {
                        //byte[] storedKey = _generationMap[i].ReadKidKeyFromValPtr(kidDef.Ptr);
                        long valueStartPtr = 0;
                        uint valueLength = 0;
                        byte[] xValue = null;
                        byte[] storedKey = null;

                        if (!this.Tree.ValuesLazyLoadingIsOn)
                        {
                            this.Tree.Cache.ReadKeyValue(useCache, kidDef.Ptr, out valueStartPtr, out valueLength, out storedKey, out xValue);
                        }
                        else
                        {
                            storedKey = this.Tree.Cache.ReadKey(useCache, kidDef.Ptr);
                        }

                       // byte[] storedKey = this.Tree.Cache.ReadKey(useCache, kidDef.Ptr);

                        if (key.Length != storedKey.Length || !key._ByteArrayEquals(storedKey))
                            return kv;

                        if (!this.Tree.ValuesLazyLoadingIsOn)
                        {
                            kv.ValueStartPointer = valueStartPtr;
                            kv.ValueFullLength = valueLength;
                            kv.Value = xValue;
                            kv.ValueIsReadOut = true;
                        }
                        kv.LinkToValue = kidDef.Ptr;
                        return kv;
                    }

                    if (i == key.Length - 1)
                        len++;

                    //iterating further
                }
                else
                    return kv;

            }

            return kv;
        }
Ejemplo n.º 4
0
        //Trying to setup kid
        /// <summary>
        /// 
        /// </summary>
        /// <param name="kid"></param>
        /// <param name="lastElementOfTheKey"></param>
        /// <param name="fullKey"></param>
        /// <param name="value"></param>
        /// <param name="useExistingPointerToValue"></param>
        /// <param name="WasUpdated">true means that value existed and was updated</param>
        /// <param name="dontUpdateIfExists">When true - if value exists, we dont update it. If WasUpdated = true then we value exists, if false - we have inserted new one</param>
        /// <returns></returns>
        public LTrieSetupKidResult SetupKidWithValue(byte kid, bool lastElementOfTheKey, ref byte[] fullKey, ref byte[] value, bool useExistingPointerToValue,out bool WasUpdated,bool dontUpdateIfExists)
        {
            //useExistingPointerToValue is used to move previously saved kid to the new place
            ToWrite = true;
            WasUpdated = false;

            LTrieSetupKidResult res = new LTrieSetupKidResult();

            byte[] ptr = null;
            LTrieKid lKid = null;

            bool tryToOverWrite = true;

            if (lastElementOfTheKey)
            {
                //We must setup Kid value
                if (!useExistingPointerToValue)     //Hack for oldKid link replacement
                {
                    //Here we also can decide if kid existed, probably we could overwrite it (in total 3 places also in the bottom)
                    lKid = KidsInNode.GetKidValue();

                    if (!lKid.Exists)
                    {
                        tryToOverWrite = false;
                        this._root.RecordsCount++;
                    }

                    WasUpdated = tryToOverWrite;

                    if (WasUpdated && dontUpdateIfExists)
                    {
                        //Value exists, but we don't want to update it
                        ptr = lKid.Ptr;
                    }
                    else
                    {
                        ptr = this.WriteKidValue(ref fullKey, ref value, tryToOverWrite, lKid.Ptr);
                    }
                }
                else
                    ptr = value;

                if (WasUpdated && dontUpdateIfExists)
                {
                    //Value exists, but we don't want to update it
                }
                else
                {
                    KidsInNode.AddKid(256, ptr);
                }

                res.ValueLink = ptr;
                res.IterateFurther = false;
                return res;
            }
            else
            {
                //If element is not the last one
                //we have to check if its kid place already resides with some other value, if yes then we have to move further.
                //And also probably move further the element who resides its place.
                //finding empty slot for our value(s). If place is empty then we save our element.

                if (KidsInNode.ContainsKid(kid))
                {
                    //When we Setup Old Kid we should never come here

                    lKid = KidsInNode.GetKid(kid);

                    if (!lKid.LinkToNode)
                    {
                        //Here we have link to the value

                        ptr = this._root.Tree.Cache.ReadKey(false, lKid.Ptr);

                        if (fullKey._ByteArrayEquals(ptr))
                        {
                            //Insert key equals to storedKey, it means - UPDATE

                            //We write for now always on the new place value and update reference
                            WasUpdated = true;

                            if (dontUpdateIfExists)
                            {
                                ptr = lKid.Ptr;
                            }
                            else
                            {
                                ptr = this.WriteKidValue(ref fullKey, ref value, true, lKid.Ptr);

                                KidsInNode.AddKid(kid, ptr);
                            }

                            res.ValueLink = ptr;
                            res.IterateFurther = false;
                            return res;
                        }
                        else
                        {
                            //Remembering old Key
                            res.KeyOldKid = ptr;
                            //Remembering old link
                            res.ValPtrOldKid = KidsInNode.ReplaceValueLinkOnKidLink(kid);
                        }

                    }

                    res.IterateFurther = true;
                    return res;
                }
                else
                {
                    //Just save this one
                    if (!useExistingPointerToValue)
                    {
                        //Here we also can decide if kid existed, probably we could overwrite it (2 places also check up there)
                        lKid = KidsInNode.GetKid(kid);

                        if (!lKid.Exists)
                        {
                            tryToOverWrite = false;
                            this._root.RecordsCount++;
                        }

                        WasUpdated = tryToOverWrite;

                        if (WasUpdated && dontUpdateIfExists)
                        {
                            //Value exists, but we don't want to update it
                            ptr = lKid.Ptr;
                        }
                        else
                        {
                            ptr = this.WriteKidValue(ref fullKey, ref value, tryToOverWrite, lKid.Ptr);
                        }
                    }
                    else
                        ptr = value;       //Hack for oldKid link replacement

                    if (WasUpdated && dontUpdateIfExists)
                    {
                        //Value exists, but we don't want to update it
                    }
                    else
                    {
                        KidsInNode.AddKid(kid, ptr);
                    }
                    res.ValueLink = ptr;
                    res.IterateFurther = false;
                    return res;
                }
            }
        }
Ejemplo n.º 5
0
        /// <summary>
        /// Will return pointer to the value of the removing kid (if it existed). Otherwise NULL.
        /// </summary>
        /// <param name="key"></param>
        /// <param name="WasRemoved">indicates that value existed if true</param>
        /// <param name="retrieveDeletedValue">indicates if we should bind deleted value to the result</param>
        /// <param name="deletedValue">interesting only if WasRemoved = true and retrieveDeletedValue is true</param>
        /// <returns></returns>
        public void RemoveKey(ref byte[] key,out bool WasRemoved, bool retrieveDeletedValue, out byte[] deletedValue)
        {
            WasRemoved = false;
            deletedValue = null;
            //if (key == null || key.Length == 0)
            //    return;

            if (key == null)
                return;

            if (key.Length > UInt16.MaxValue)
                throw DBreezeException.Throw(DBreezeException.eDBreezeExceptions.KEY_IS_TOO_LONG);

            LTrieGenerationNode gn = null;

            if (_generationMap.Count() == 0)
            {
                //Loading it from Link TO ZERO Pointer
                gn = new LTrieGenerationNode(this);
                gn.Pointer = this.LinkToZeroNode;
                //gn.Value=0; - default
                _generationMap.Add(0, gn);

                gn.ReadSelf(false, null);
            }

            LTrieSetupKidResult res = new LTrieSetupKidResult();

            //byte[] key1 = null; //we need it as null
            //byte[] val1 = null;

            //len can be expanded inside of the algorithm maximum by one
            int len = key.Length;

            bool cleanCheck = true;

            bool iterateFurther = false;

            /*SPECIAL CASE key=byte[0]*/
            if (key.Length == 0)
            {
                _generationMap[0].RemoveKid((byte)0, true, ref key, out WasRemoved, retrieveDeletedValue, out deletedValue);

                return;
            }
            /***************************/

            for (int i = 0; i < len; i++)
            {
                //Getting kid from actual generation map

                if (cleanCheck && i != 0 && _generationMap.ContainsKey(i) && _generationMap[i].Value != key[i - 1])
                {
                    cleanCheck = false;

                    //In case if i>0, it's not the first element and we have to compare if there are generation mapsstarting from this point.
                    //If generationMap[i] exists and it's value not that what we want, we have to clean full in memory generation map as

                    //Save_node... up to i
                    Save_GM_nodes_Starting_From(i);

                    //Remove Gen Map starting from... i
                    _generationMap.RemoveBiggerOrEqualThenKey(i);
                }

                if (!_generationMap.ContainsKey(i))
                {
                    //All ok, for the first generation node

                    //We read or create generation map
                    //And add it to the _generationMap

                    gn = new LTrieGenerationNode(this);
                    gn.Value = key[i - 1];
                    gn.Pointer = _generationMap[i - 1].KidsInNode.GetPointerToTheKid(key[i - 1]);
                    //gn.Pointer = _generationMap[i - 1].GetKidPointer(key[i - 1]);

                    _generationMap.Add(i, gn);

                    if (gn.Pointer != null)
                        gn.ReadSelf(false, null);
                    else
                        gn.Pointer = new byte[DefaultPointerLen];       //!!!!!!!!!!!!! Check if it'S really necessary or we can leave it as null
                }

                //Trying to remove as a result we receive information if we should iterate further
                iterateFurther = _generationMap[i].RemoveKid((i == key.Length) ? (byte)0 : key[i], (i == key.Length), ref key, out WasRemoved, retrieveDeletedValue, out deletedValue);

                if (!iterateFurther)
                {
                    break;
                }
                else
                {
                    if (i == (key.Length - 1))
                        len++;
                }
            }
        }