All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scudata.dw.MemoryTable Maven / Gradle / Ivy

Go to download

SPL(Structured Process Language) A programming language specially for structured data computing.

There is a newer version: 20241126
Show newest version
package com.scudata.dw;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

import com.scudata.array.IArray;
import com.scudata.common.IntArrayList;
import com.scudata.common.MessageManager;
import com.scudata.common.RQException;
import com.scudata.dm.BaseRecord;
import com.scudata.dm.CompressIndexTable;
import com.scudata.dm.Context;
import com.scudata.dm.DataStruct;
import com.scudata.dm.IndexTable;
import com.scudata.dm.Record;
import com.scudata.dm.Sequence;
import com.scudata.dm.Table;
import com.scudata.dm.cursor.ICursor;
import com.scudata.dm.cursor.MemoryCursor;
import com.scudata.dm.cursor.MultipathCursors;
import com.scudata.dw.compress.ColumnList;
import com.scudata.expression.Expression;
import com.scudata.expression.IParam;
import com.scudata.expression.Node;
import com.scudata.expression.fn.string.Like;
import com.scudata.expression.mfn.sequence.Contain;
import com.scudata.expression.operator.DotOperator;
import com.scudata.resources.EngineMessage;

/**
 * ?ڱ???
 * @author runqian
 *
 */
public class MemoryTable extends Table {
	private static final long serialVersionUID = 0x03310004;
	
	// ????зֲ?????ʽ???????ڽڵ?????Ƿֲ??ģ????û????Ҫ????????????Ҫ?ȽϽڵ???????ݵķ?Χ?Ƿ??غ?
	private String distribute; // ?ֲ?????ʽ
	private int part = -1; // ?????ķֱ?
	
	private int []segmentFields; // ???ɶ?·?α?ʱ???ڷֶε??ֶ?
	private List indexs;
	
	/**
	 * ???л?ʱʹ??
	 */
	public MemoryTable() {}

	/**
	 * ????
	 * @param fields String[] ???е???ͨ?ֶ?
	 * @return Table
	 */
	public MemoryTable(String []fields) {
		super(fields);
	}

	public MemoryTable(DataStruct ds) {
		super(ds);
	}

	public MemoryTable(String []fields, int initialCapacity) {
		super(fields, initialCapacity);
	}

	public MemoryTable(DataStruct ds, int initialCapacity) {
		super(ds, initialCapacity);
	}
	
	public MemoryTable(Table table) {
		this.ds = table.dataStruct();
		this.mems = table.getMems();
	}
	
	/**
	 * ????ѹ???ڴ??
	 * cursor??ļ?¼?????ȥ
	 * @param cursor
	 */
	public MemoryTable(ICursor cursor) {
		this.mems = new ColumnList(cursor);
		this.ds = ((ColumnList)mems).dataStruct();
		if (ds == null) return;
		int index[] = ds.getPKIndex();
		if (index == null) return;
		CompressIndexTable indexTable = new CompressIndexTable((ColumnList) mems, index);
		this.setIndexTable(indexTable);
	}
	
	/**
	 * ????ѹ???ڴ??
	 * cursor??ȡn????¼?????ȥ
	 * @param cursor
	 * @param n
	 */
	public MemoryTable(ICursor cursor, int n) {
		this.mems = new ColumnList(cursor, n);
		this.ds = ((ColumnList)mems).dataStruct();
		if (ds == null) return;
		int index[] = ds.getPKIndex();
		if (index == null) return;
		CompressIndexTable indexTable = new CompressIndexTable((ColumnList) mems, index);
		this.setIndexTable(indexTable);
	}

	/**
	 * ?Ƿ???ѹ??????ѹ????????????ʱ???????????
	 * @return
	 */
	public boolean isCompressTable() {
		return mems instanceof ColumnList;
	}
	
	/**
	 * ׷??
	 * @param table
	 */
	public Sequence append(Sequence table) {
		IArray addMems = table.getMems();

		// ???ļ?¼?????????к????
		DataStruct ds = this.ds;
		for (int i = 1, addCount = addMems.size(); i <= addCount; ++i) {
			Record r = (Record)addMems.get(i);
			r.setDataStruct(ds);
		}

		mems.addAll(addMems);
		return this;
	}
	
	/**
	 * ????
	 * @param data
	 * @param opt
	 * @return
	 */
	public Sequence update(Sequence data, String opt) {
		boolean isInsert = true;
		boolean isUpdate = true;
		Sequence result = null;
		if (opt != null) {
			if (opt.indexOf('i') != -1) isUpdate = false;
			if (opt.indexOf('u') != -1) {
				if (!isUpdate) {
					MessageManager mm = EngineMessage.get();
					throw new RQException(opt + mm.getMessage("engine.optConflict"));
				}
				
				isInsert = false;
			}
			
			if (opt.indexOf('n') != -1) result = new Sequence();
		}
		
		DataStruct ds = data.dataStruct();
		if (ds == null) {
			MessageManager mm = EngineMessage.get();
			throw new RQException(mm.getMessage("engine.needPurePmt"));
		}
		
		if (!ds.isCompatible(this.ds)) {
			MessageManager mm = EngineMessage.get();
			throw new RQException(mm.getMessage("engine.dsNotMatch"));
		}
		
		int oldLen = length();
		if (oldLen == 0) {
			if (isInsert) {
				append(data);
				if (result != null) {
					result.addAll(data);
				}
			}
			
			if (result == null) {
				return this;
			} else {
				return result;
			}
		}
		
		ds = this.ds;
		int []keyIndex = ds.getPKIndex();
		if (keyIndex == null) {
			MessageManager mm = EngineMessage.get();
			throw new RQException(mm.getMessage("ds.lessKey"));
		}
		
		int keyCount = keyIndex.length;
		int len = data.length();
		int []seqs = new int[len + 1];
		
		if (keyCount == 1) {
			int k = keyIndex[0];
			for (int i = 1; i <= len; ++i) {
				Record r = (Record)data.getMem(i);
				seqs[i] = pfindByKey(r.getNormalFieldValue(k), true);
			}
		} else {
			Object []keyValues = new Object[keyCount];
			for (int i = 1; i <= len; ++i) {
				Record r = (Record)data.getMem(i);
				for (int k = 0; k < keyCount; ++k) {
					keyValues[k] = r.getNormalFieldValue(keyIndex[k]);
				}
				
				seqs[i] = pfindByFields(keyValues, keyIndex);
			}
		}
		
		// ??Ҫ????????ĵ???append׷??
		IArray mems = this.mems;
		for (int i = 1; i <= len; ++i) {
			Record r = (Record)data.getMem(i);
			if (seqs[i] > 0) {
				if (isUpdate) {
					Record sr = (Record)mems.get(seqs[i]);
					sr.set(r);
					if (result != null) {
						result.add(r);
					}
				}
			} else if (isInsert) {
				r = new Record(ds, r.getFieldValues());
				mems.add(r);
				if (result != null) {
					result.add(r);
				}
			}
		}
		
		if (mems.size() > oldLen) {
			sortFields(keyIndex);
		}
		
		rebuildIndexTable();
		
		if (result == null) {
			return this;
		} else {
			return result;
		}
	}
	
	/**
	 * ɾ??
	 */
	public Sequence delete(Sequence data, String opt) {
		if (data == null || data.length() == 0) {
			if (opt == null || opt.indexOf('n') == -1) {
				return this;
			} else {
				return new Sequence(0);
			}
		}

		String []pks = getPrimary();
		if (pks == null) {
			MessageManager mm = EngineMessage.get();
			throw new RQException(mm.getMessage("ds.lessKey"));
		}
		
		DataStruct ds = data.dataStruct();
		if (ds == null) {
			MessageManager mm = EngineMessage.get();
			throw new RQException(mm.getMessage("engine.needPurePmt"));
		}
		
		int keyCount = pks.length;
		int []keyIndex = new int[keyCount];
		for (int k = 0; k < keyCount; ++k) {
			keyIndex[k] = ds.getFieldIndex(pks[k]);
			if (keyIndex[k] < 0) {
				MessageManager mm = EngineMessage.get();
				throw new RQException(pks[k] + mm.getMessage("ds.fieldNotExist"));
			}
		}
		
		IArray mems = this.mems;
		int delCount = 0;

		IArray dataMems = data.getMems();
		int count = dataMems.size();
		int []index = new int[count];
		Sequence delete = null;
		if (opt != null && opt.indexOf('n') != -1) {
			delete = new Sequence(count);
		}

		if (keyCount == 1) {
			// ????Ҫɾ???ļ?¼???????е?λ??
			int ki = keyIndex[0];
			for (int i = 1; i <= count; ++i) {
				BaseRecord r = (BaseRecord)dataMems.get(i);
				int seq = pfindByKey(r.getNormalFieldValue(ki), true);
				if (seq > 0) {
					index[delCount] = seq;
					delCount++;
					if (delete != null) {
						delete.add(r);
					}
				}
			}
		} else {
			// ????Ҫɾ???ļ?¼???????е?λ??
			int []srcPKIndex = this.ds.getPKIndex();
			Object []keyValues = new Object[keyCount];
			for (int i = 1; i <= count; ++i) {
				BaseRecord r = (BaseRecord)dataMems.get(i);
				for (int k = 0; k < keyCount; ++k) {
					keyValues[k] = r.getNormalFieldValue(keyIndex[k]);
				}
				
				int seq = pfindByFields(keyValues, srcPKIndex);
				if (seq > 0) {
					index[delCount] = seq;
					delCount++;
					if (delete != null) {
						delete.add(r);
					}
				}
			}
		}

		if (delCount == 0) {
			if (opt == null || opt.indexOf('n') == -1) {
				return this;
			} else {
				return new Sequence(0);
			}
		}

		if (delCount < count) {
			int []tmp = new int[delCount];
			System.arraycopy(index, 0, tmp, 0, delCount);
			index = tmp;
		}

		// ??????????????
		Arrays.sort(index);
		mems.remove(index);

		rebuildIndexTable();

		if (delete == null) {
			return this;
		} else {
			return delete;
		}
	}

	/**
	 * ????
	 */
	public Object findByKey(Object key, boolean isSorted) {
		IndexTable indexTable = getIndexTable();
		if (indexTable == null) {
			int index = pfindByKey(key, true);
			return index > 0 ? mems.get(index) : null;
		} else {
			if (key instanceof Sequence) {
				// key???????ӱ??ļ?¼????????????B
				if (length() == 0) {
					return null;
				}
				
				Object startVal = mems.get(1);
				if (startVal instanceof BaseRecord) {
					startVal = ((BaseRecord)startVal).getPKValue();
				}
				
				Sequence seq = (Sequence)key;
				int klen = seq.length();
				if (klen == 0) {
					return 0;
				}
				
				if (startVal instanceof Sequence) {
					int klen2 = ((Sequence)startVal).length();
					if (klen2 == 1) {
						return indexTable.find(seq.getMem(1));
					} else if (klen > klen2) {
						Object []vals = new Object[klen2];
						for (int i = 1; i <= klen2; ++i) {
							vals[i - 1] = seq.getMem(i);
						}

						return indexTable.find(vals);
					} else {
						return indexTable.find(seq.toArray());
					}
				} else {
					return indexTable.find(seq.getMem(1));
				}
			} else {
				return indexTable.find(key);
			}
		}
	}
	
	/**
	 * ???÷ֱ?????ʽ
	 * @param exp ?ֱ?????ʽ
	 */
	public void setDistribute(String exp) {
		distribute = exp;
	}
	
	/**
	 * ȡ?ֲ?????ʽ
	 * @return
	 */
	public String getDistribute() {
		return distribute;
	}
	
	/**
	 * ???÷ֱ???
	 * @param part ?ֱ???
	 */
	public void setPart(int part) {
		this.part = part;
	}
	
	/**
	 * ȡ?ֱ???
	 * @return
	 */
	public int getPart() {
		return part;
	}
	
	/**
	 * ???÷ֶ??ֶ?
	 * @param fields
	 */
	public void setSegmentFields(String []fields) {
		IntArrayList list = new IntArrayList(fields.length);
		for (String field : fields) {
			int f = ds.getFieldIndex(field);
			if (f != -1) {
				list.addInt(f);
			}
		}
		
		if (list.size() > 0) {
			segmentFields = list.toIntArray();
		}
	}
	
	/**
	 * ???õ?һ???ֶ?Ϊ?ֶ??ֶ?
	 */
	public void setSegmentField1() {
		segmentFields = new int[] {0};
	}
	
	/**
	 * ȡ?ֶ??ֶ?????
	 * @return
	 */
	public int[] getSegmentFields() {
		return segmentFields;
	}
	
	/**
	 * ??????һ?εĿ?ʼλ??
	 * @param i ?к?
	 * @param segmentFields ?ֶ??ֶ?
	 * @return
	 */
	private int getSegmentEnd(int i, int []segmentFields) {
		BaseRecord r = (BaseRecord)getMem(i);
		int len = length();
		for (++i; i <= len; ++i) {
			BaseRecord record = (BaseRecord)getMem(i);
			if (!r.isEquals(record, segmentFields)) {
				return i;
			}
		}
		
		return len + 1;
	}
	
	public ICursor cursor(int segSeq, int segCount, Context ctx) {
		if (segCount <= 1) {
			return new MemoryCursor(this);
		}

		// ??????·?α?
		int len = length();
		int blockSize = len / segCount;
		int []segmentFields = this.segmentFields;
		
		if (segSeq < 1) {
			if (blockSize < 0) {
				return new MemoryCursor(this);
			}
			
			ICursor []cursors = new ICursor[segCount];
			int start = 1; // ????
			int end; // ??????
			
			if (segmentFields == null) {
				for (int i = 1; i <= segCount; ++i) {
					if (i == segCount) {
						end = len + 1;
					} else {
						end = start + blockSize;
					}
					
					cursors[i - 1] = new MemoryCursor(this, start, end);
					start = end;
				}
			} else {
				// ?зֶ??ֶ?ʱ???ֶ??ֶ?ֵ??ͬ?IJ??ᱻ???????α?
				for (int i = 1; i <= segCount; ++i) {
					if (i == segCount) {
						end = len + 1;
					} else {
						end = blockSize * i;
						if (start <= end) {
							end = getSegmentEnd(end, segmentFields);
						}
					}
					
					cursors[i - 1] = new MemoryCursor(this, start, end);
					start = end;
				}
			}
			
			return new MultipathCursors(cursors, ctx);
		} else {
			// ?????ֶ??α?
			int start = 1; // ????
			int end; // ??????
			if (segSeq == segCount) {
				start = blockSize * (segSeq - 1) + 1;
				end = len + 1;
			} else {
				start = blockSize * (segSeq - 1) + 1;
				end = start + blockSize;
			}
			
			if (segmentFields != null) {
				if (start > 1) {
					start = getSegmentEnd(start - 1, segmentFields);
				}
				
				if (start < end) {
					end = getSegmentEnd(end - 1, segmentFields);
				}
			}
			
			return new MemoryCursor(this, start, end);
		}
	}
	
	public MemoryTableIndex getIndex(String name) {
		List indexs = this.indexs;
		if (indexs == null || indexs.size() == 0) {
			return null;
		}
		for (MemoryTableIndex index : indexs) {
			if (index.getByName(name)) {
				return index;
			}
		}
		return null;
	}
	/**
	 * ?½?????
	 * @param I ????????
	 * @param fields ?ֶ?????
	 * @param obj ??KV????ʱ??ʾֵ?ֶ????ƣ???hash????ʱ??ʾhash?ܶ?
	 * @param opt ????'a'ʱ??ʾ׷??, ????'r'ʱ??ʾ?ؽ?????
	 * @param w ????ʱ?Ĺ???????
	 * @param ctx ??????
	 */
	public void createIMemoryTableIndex(String I, String []fields, Object obj, String opt, Expression w, Context ctx) {
		if (getIndex(I) != null) {
			MessageManager mm = EngineMessage.get();
			throw new RQException(I + " " + mm.getMessage("dw.indexNameAlreadyExist"));
		}
		
		List indexs = this.indexs;
		if (indexs == null) {
			this.indexs = indexs = new ArrayList();
		}
		if (obj == null) {
			if  (opt != null) {
				//ȫ??
				if  (opt.indexOf('w') != -1) {
					MemoryTableIndex index = new MemoryTableIndex(I, this, fields, w, 0, MemoryTableIndex.TYPE_FULLTEXT, ctx);
					indexs.add(index);
					return;
				}
				MessageManager mm = EngineMessage.get();
				throw new RQException("index" + mm.getMessage("function.invalidParam"));
			}
			
			//????
			MemoryTableIndex index = new MemoryTableIndex(I, this, fields, w, 0, MemoryTableIndex.TYPE_SORT, ctx);
			indexs.add(index);
		} else if (obj instanceof String[]) {
			//KV
			MemoryTableIndex index = new MemoryTableIndex(I, this, fields, w, 0, MemoryTableIndex.TYPE_SORT, ctx);
			indexs.add(index);
		} else if (obj instanceof Integer) {
			//hash
			MemoryTableIndex index = new MemoryTableIndex(I, this, fields, w, (Integer) obj, MemoryTableIndex.TYPE_HASH, ctx);
			indexs.add(index);
		}
	}
	
	/**
	 * ????Ҫ???????ֶ?ѡ??һ?????ʵ??????????֣?û?к??ʵ??򷵻ؿ?
	 * @param fieldNames
	 * @return
	 */
	private String chooseIndex(String[] fieldNames) {
		if (fieldNames == null || indexs == null)
			return null;
		ArrayList list = new ArrayList();
		int count = indexs.size();
		int fcount = fieldNames.length;
		for (int i = 0; i < count; i++) {
			String[] ifields = indexs.get(i).getIfields();
			int cnt = ifields.length;
			if (cnt < fcount)
				continue;
			list.clear();
			for (int j = 0; j < fcount; j++) {
				list.add(ifields[j]);
			}
			for (String str : fieldNames) {
				list.remove(str);
			}
			if (list.isEmpty()) {
				return indexs.get(i).getName();
			}
		}
		return null;
	}
	
	/**
	 * ??????ѯ????icursor?????
	 */
	public ICursor icursor(String []fields, Expression filter, String iname, String opt, Context ctx) {
		MemoryTableIndex index = null;
		if (iname != null) {
			index = this.getIndex(iname);
			if (index == null) {
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("dw.indexNotExist") + " : " + iname);
			}
		} else {
			String[] indexFields;
			if (filter.getHome() instanceof DotOperator) {
				Node right = filter.getHome().getRight();
				if (!(right instanceof Contain)) {
					MessageManager mm = EngineMessage.get();
					throw new RQException("icursor" + mm.getMessage("function.invalidParam"));
				}
				String str = ((Contain)right).getParamString();
				str = str.replaceAll("\\[", "");
				str = str.replaceAll("\\]", "");
				str = str.replaceAll(" ", "");
				indexFields = str.split(",");
			} else if (filter.getHome() instanceof Like) {
				IParam sub1 = ((Like) filter.getHome()).getParam().getSub(0);
				String f = (String) sub1.getLeafExpression().getIdentifierName();
				indexFields = new String[]{f};
			} else {
				indexFields = PhyTable.getExpFields(filter, ds.getFieldNames());
			}
			String indexName = chooseIndex(indexFields);
			if (indexFields == null || indexName == null) {
				//filter?в??????κ??ֶ? or ??????????
				MessageManager mm = EngineMessage.get();
				throw new RQException("icursor" + mm.getMessage("function.invalidParam"));
			}
			index = getIndex(indexName);
		}

		ICursor cursor = index.select(filter, fields, opt, ctx);
		return cursor;
	}
	
	/**
	 * ??????ѯ????ifind?????
	 */
	public Object ifind(Object key, String iname, String opt, Context ctx) {
		MemoryTableIndex index = null;
		index = this.getIndex(iname);
		if (index == null) {
			MessageManager mm = EngineMessage.get();
			throw new RQException("ifind" + mm.getMessage("dw.indexNotExist") + " : " + iname);
		}
		return index.ifind(key, opt, ctx);
	}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy