/// <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++; } } } }
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; } } }
/// <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; }
//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; } } }
/// <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++; } } }