Exemplo n.º 1
0
		/// <summary>
		/// Open
		/// </summary>
		/// <param name="fname"></param>
		public void Open(string fname)
		{
			lock(this.TableBlocking)
			{
				RaiseExceptionIfOpened();
				if(fname.ToLower().EndsWith(".hnd"))
					fname=fname.Substring(0,fname.Length-4);
				DatabaseFilePath=System.IO.Path.GetFullPath(fname)+".hnd";

				// Initial values
				if(!File.Exists(this.DatabaseFilePath))
				{
					try
					{
						fsDB = new FileStream(this.DatabaseFilePath,FileMode.Create,FileAccess.ReadWrite,FileShare.None,8*1024);
					}
					catch
					{
						throw new Exception("Can't create file.");
					}
				}
				else
				{
					try
					{
						fsDB = new FileStream(this.DatabaseFilePath,FileMode.Open,FileAccess.ReadWrite,FileShare.None,8*1024);
					}
					catch
					{
						throw new Exception("Database in use.");
					}
				}
				long len = (fsDB.Length/PageSize); len*=PageSize;
				if(fsDB.Length>len)
				{
					this.LogToFile("Warning","File size fixed.");
					fsDB.SetLength(len);
				}
				slFID2Pages = new SortedList();
				TableName2TID = new Hashtable();
				TID2Def = new Hashtable();
				pcInit();
				//PagesInUse = new SortedSet();
				DeletedPages = new SortedSet();
				br = new BinaryReader(fsDB,System.Text.Encoding.Unicode);
				bw = new BinaryWriter(fsDB,System.Text.Encoding.Unicode);

				// check log file
				if(true)
				{
					string lfn = DatabaseFilePath+".hlg";
					if(File.Exists(lfn))
					{
						FileStream lf = new FileStream(lfn,FileMode.Open,FileAccess.ReadWrite,FileShare.None);
						BinaryReader lfr = new BinaryReader(lf,System.Text.Encoding.Unicode);
						try
						{
							if((lfr.BaseStream.Length>0)&&lfr.ReadBoolean())
							{// recover from last crash
								byte logtype = lfr.ReadByte();
								if(logtype==0)
								{// delete pages op
									this.LogToFile("Warning","Deleted pages fixed.");
									ArrayList al = new ArrayList();
									int cnt = lfr.ReadInt32();
									for(int n=0;n<cnt;n++)
									{
										al.Add( lfr.ReadInt32() );
									}
									for(int n=0;n<cnt;n++)
									{
										bw.BaseStream.Position=PageSize*( (int)al[n] );
										bw.Write( true ); // deleted
									}
									bw.Flush();
									lf.SetLength(0);
									lf.Flush();
								}
								if(logtype==1)
								{// rollback pages
									this.LogToFile("Warning","Rollback modified pages.");
									int pcount = lfr.ReadInt32(); // num of pages

									for(int p=0;p<pcount;p++)
									{
										int page = lfr.ReadInt32();
										fsDB.Position=PageSize*page;
										byte[] buf = lfr.ReadBytes( Database.PageSize );
										bw.Write( buf );
									}

									bw.Flush();
									lf.SetLength(0);
									lf.Flush();
								}
							}
						}
						catch
						{
							Close();
							throw new Exception("Can't recover from last crash.");
						}
						finally
						{
							lf.Close();
						}
					}
				}
				ArrayList pagePurgatory = new ArrayList();
				Hashtable htFieldsByTID = new Hashtable();// contains Hastables by field seq
				Hashtable htDataByTID = new Hashtable(); // key: tid + fieldseq + dataseq = pageno
				Set ProcessedPages = new SortedSet();
				#region 1st Pass: Scan deleted pages and table pages
				NextFID=-1;
				try
				{
					int pos=0; // page counter
					fsDB.Position=0;
					while(fsDB.Position<fsDB.Length)
					{	
						// leemos info de página
						long ptr = br.BaseStream.Position;
						bool bPageIsDeleted = br.ReadBoolean();
						if(bPageIsDeleted)
						{
							ProcessedPages.Add(pos);
							this.DeletedPages.Add(pos);
						}
						else
						{
							byte bPageType = br.ReadByte();
							int fid = br.ReadInt32();
							if(bPageType==TablePageType)
							{
								ProcessedPages.Add(pos);
								TableNameDef tnd = new TableNameDef(fid,pos);
								tnd.fseq=br.ReadInt32();
								tnd.rownum=br.ReadInt64();
								tnd.tname = br.ReadString();
								TID2Def[fid]=tnd;
								TableName2TID[tnd.tname]=fid;
							}
							else if(bPageType==FieldPageType)
							{// Page is a field def, store it for further processing
								ProcessedPages.Add(pos);
								int tid = fid;
								//TableNameDef tnd = TID2Def[tid] as TableNameDef;
								Field fld = new Field();
								fld.Read(br);// 4-field
								fld.tid=tid;
								fld.PageOfFieldSef=pos;

								if(!htFieldsByTID.ContainsKey(tid))
									htFieldsByTID[tid]=new Hashtable();
								Hashtable htFieldsBySeq = htFieldsByTID[tid] as Hashtable;

								// avoid repeated fields
								bool bAvoid=false;
								foreach(Field f in htFieldsBySeq.Values)
								{
									if(f.Name==fld.Name)
									{
										bAvoid=true;
										break;
									}
								}
								if(!bAvoid)
								{
									htFieldsBySeq[fld.seq]=fld;
									//tnd.fseq2FieldDef[fld.seq]=fld;
								}
								else
								{
									pagePurgatory.Add(pos);
								}
							}
							else if(bPageType==ContentPageType)
							{ 
								int tid = fid;
								if(!htDataByTID.ContainsKey(tid))
									htDataByTID[tid]=new Hashtable();
								Hashtable htDataByFSeq = htDataByTID[tid] as Hashtable;

								long fseq = br.ReadInt32(); // 4º seq of field
								if(!htDataByFSeq.ContainsKey(fseq))
									htDataByFSeq[fseq]=new ArrayList();
								ArrayList alDataByOrder = htDataByFSeq[fseq] as ArrayList;

								int seq = br.ReadInt32(); // 5º data page order
								while(alDataByOrder.Count<=seq)
									alDataByOrder.Add(-1);
								alDataByOrder[seq]=pos;
							}
							NextFID = Math.Max( NextFID, fid );
							PeekPagesByFID(fid).Add(pos);
						}
						fsDB.Position = Database.PageSize + ptr;
						pos++;
					}
					NextFID++;
				}
				catch(Exception ex)
				{
					this.LogToFile(ex.Message,ex.StackTrace);
					this.Close();
					throw new Exception("Database corrupted.");
				}
				#endregion
				#region 2nd Pass: Field integration
//				try
//				{
					foreach(int tid in htFieldsByTID.Keys)
					{
						TableNameDef tnd = TID2Def[tid] as TableNameDef;
						Hashtable htFieldsBySeq = htFieldsByTID[tid] as Hashtable;
						foreach(long seq in htFieldsBySeq.Keys)
						{
							tnd.fseq2FieldDef[seq]=htFieldsBySeq[seq];
						}
					}
//
//					int pos=0; // page counter
//					fsDB.Position=0;
//					while(fsDB.Position<fsDB.Length)
//					{	
//						// leemos info de página
//						long ptr = br.BaseStream.Position;
//						if(!ProcessedPages.Contains(pos))
//						{
//							bool bPageIsDeleted = br.ReadBoolean();// 1-deleted
//							if(bPageIsDeleted)
//							{
//								// skip
//							}
//							else
//							{
//								byte bPageType = br.ReadByte();// 2-type
//								int tid = br.ReadInt32(); // 3-fid of table
//								if(bPageType==FieldPageType)
//								{
//									ProcessedPages.Add(pos);
//									TableNameDef tnd = TID2Def[tid] as TableNameDef;
//									Field fld = new Field();
//									fld.Read(br);// 4-field
//									fld.tid=tid;
//									fld.PageOfFieldSef=pos;
//
//									// avoid repeated fields
//									bool bAvoid=false;
//									foreach(Field f in tnd.fseq2FieldDef.Values)
//									{
//										if(f.Name==fld.Name)
//										{
//											bAvoid=true;
//											break;
//										}
//									}
//									if(!bAvoid)
//									{
//										tnd.fseq2FieldDef[fld.seq]=fld;
//									}
//									else
//									{
//										pagePurgatory.Add(pos);
//									}
//								}
//							}
//						}
//						fsDB.Position = Database.PageSize + ptr;
//						pos++;
//					}
//				}
//				catch(Exception ex)
//				{
//					this.LogToFile(ex.Message,ex.StackTrace);
//					this.Close();
//					throw new Exception("Database corrupted.");
//				}
				#endregion
				#region 3nd Pass: Locate data for fields
				try
				{
					foreach(int tid in htDataByTID.Keys)
					{
						TableNameDef tnd = TID2Def[tid] as TableNameDef;
						Hashtable htDataByFSeq = htDataByTID[tid] as Hashtable;
						foreach(long seq in htDataByFSeq.Keys)
						{
							ArrayList alDataByOrder = htDataByFSeq[seq] as ArrayList;
							if(!tnd.fseq2FieldDef.ContainsKey(seq))
							{
								pagePurgatory.AddRange( alDataByOrder );
							}
							else
							{
								Field fld = tnd.fseq2FieldDef[seq] as Field;
								fld.DataFID=alDataByOrder;
							}
						}
					}
//					int pos=0; // page counter
//					fsDB.Position=0;
//					while(fsDB.Position<fsDB.Length)
//					{	
//						// leemos info de página
//						long ptr = br.BaseStream.Position;
//						if(!ProcessedPages.Contains(pos))
//						{
//							bool bPageIsDeleted = br.ReadBoolean();// 1º deleted is on?
//							if(bPageIsDeleted)
//							{
//								// skip
//							}
//							else
//							{
//								byte bPageType = br.ReadByte();// 2º Type
//								int tid = br.ReadInt32();// 3º fid of table
//								if(bPageType==ContentPageType)
//								{ 
//									long fseq = br.ReadInt32(); // 4º seq of field
//									int seq = br.ReadInt32(); // 5º data page order
//									TableNameDef tnd = TID2Def[tid] as TableNameDef;
//									if(!tnd.fseq2FieldDef.ContainsKey(fseq))
//									{
//										pagePurgatory.Add(pos);
//									}
//									Field fld = tnd.fseq2FieldDef[fseq] as Field;
//									while(fld.DataFID.Count<=seq)
//										fld.DataFID.Add(-1);
//									fld.DataFID[seq]=pos;
//								}
//							}
//						}
//						fsDB.Position = Database.PageSize + ptr;
//						pos++;
//					}
					foreach(TableNameDef tnd in TID2Def.Values)
						foreach(Field f in tnd.fseq2FieldDef.Values)
							foreach(int page in f.DataFID)
								if(page==-1)
									throw new Exception("Database corrupted.");
				}
				catch(Exception ex)
				{
					this.LogToFile(ex.Message,ex.StackTrace);
					this.Close();
					throw new Exception("Database corrupted.");
				}
				#endregion
				foreach(TableNameDef tnd in TID2Def.Values)
					foreach(Field f in tnd.fseq2FieldDef.Values)
					{
						// grow if it is needed
						if(tnd.rownum>0)
						{
							int valSize = (int)f.DataSize();
							long Capacity = (PageSize-ContentPageDataOffset)/valSize;
							ArrayList pages = f.DataFID;
							while((pages.Count*Capacity)<tnd.rownum)
							{
								int datapage = this.LockAvaiblePage();
								bw.BaseStream.Position = (datapage*PageSize);
								bw.Write( true );
								bw.Flush();
								bw.Write( (byte)Database.ContentPageType );
								bw.Write( tnd.TableFID );
								bw.Write( (int)f.seq );
								bw.Write( f.DataFID.Count );
								bw.Flush();
								for(int c=0;c<Capacity;c++)
								{
									bw.BaseStream.Position = (datapage*PageSize)+ContentPageDataOffset+c*valSize;
									f.WriteDefaultData(bw,false);
								}
								bw.Flush();
								bw.BaseStream.Position = (datapage*PageSize);
								bw.Write( (bool)false );
								bw.Flush();
								pages.Add(datapage);
								PeekPagesByFID(tnd.TableFID).Add(datapage);
								this.InvalidatePage(datapage);
							}
						}
					}


				// Autoseq table
				this.AddTableIfNotExist(tblSequences);
				this.AddFieldIfNotExist(tblSequences, new Field("SEQNAME","",FieldIndexing.Unique,40));
				this.AddFieldIfNotExist(tblSequences, new Field("SEQVALUE",(long)0,FieldIndexing.None));
				this.AddFieldIfNotExist(tblSequences, new Field("SEQINCREMENT",(long)1,FieldIndexing.None));
				this.AddFieldIfNotExist(tblSequences, new Field("SEQLOOP",false,FieldIndexing.None));
				this.AddFieldIfNotExist(tblSequences, new Field("SEQMAXVALUE",long.MaxValue,FieldIndexing.None));

				// Autoseq table
				this.AddTableIfNotExist(tblAlterTbl);
				this.AddFieldIfNotExist(tblAlterTbl, new Field("TNAME","",FieldIndexing.None,80));
				this.AddFieldIfNotExist(tblAlterTbl, new Field("FSRC","",FieldIndexing.None,80));
				this.AddFieldIfNotExist(tblAlterTbl, new Field("FTMP","",FieldIndexing.None,80));
				this.AddFieldIfNotExist(tblAlterTbl, new Field("STATE",(int)1,FieldIndexing.None));

				// Unknown bugfix -> Purge pages
				foreach(int i in pagePurgatory)
				{
					if(i==-1) continue;
					bw.BaseStream.Position = (i*PageSize);
					bw.Write( true );
					bw.Flush();
				}
			}
			GC.Collect();
			GC.WaitForPendingFinalizers();
		}
Exemplo n.º 2
0
		/// <summary>
		/// Adds a table
		/// </summary>
		public void AddTable(string Name)
		{
			lock(this.TableBlocking)
			{
				this.RaiseExceptionIfClosed();
				if(TableName2TID.Contains(Name))
					throw new Exception("Table already present.");

				int TablePage = LockAvaiblePage();

				TableNameDef tnd=null;
				try
				{
					this.fsDB.Position = TablePage * PageSize;
					bw.Write( (bool)true ); // deleted
					bw.Flush();
					bw.Write( (byte)TablePageType ); // pagetype
					int tid = this.NextFID++;
					bw.Write( (int)tid ); // tid

					tnd = new TableNameDef(tid,TablePage);
					tnd.fseq=0;
					bw.Write( tnd.fseq );
					tnd.rownum=0;
					bw.Write( tnd.rownum );
					tnd.tname=Name;
					bw.Write( tnd.tname );
					bw.Flush();

					this.fsDB.Position = TablePage * PageSize;
					bw.Write( (bool)false ); // non-deleted
					bw.Flush();
					TID2Def[tid]=tnd;
					TableName2TID[tnd.tname]=tid;
					PeekPagesByFID(tid).Add(TablePage);
				}
				catch(Exception ex)
				{
					this.LogToFile(ex.Message,ex.StackTrace);
					throw new Exception("Write error.");
				}
				Field f = new Field(DeletedFieldName,true,FieldIndexing.IndexedNotUnique);
				AddField(tnd.tname,f);
			}
		}