diff options
Diffstat (limited to 'core/vm/sqlvm/common/storage.go')
-rw-r--r-- | core/vm/sqlvm/common/storage.go | 149 |
1 files changed, 98 insertions, 51 deletions
diff --git a/core/vm/sqlvm/common/storage.go b/core/vm/sqlvm/common/storage.go index e046b0411..be8a074ad 100644 --- a/core/vm/sqlvm/common/storage.go +++ b/core/vm/sqlvm/common/storage.go @@ -534,43 +534,99 @@ func (s *Storage) IncSequence( return val } -// DecodePKHeader decodes primary key hash header to lastRowID and rowCount. -func (s *Storage) DecodePKHeader(header common.Hash) (lastRowID, rowCount uint64) { - lastRowID = binary.BigEndian.Uint64(header[:8]) - rowCount = binary.BigEndian.Uint64(header[8:16]) - return +func setBit(n byte, pos uint) byte { + n |= (1 << pos) + return n } -// EncodePKHeader encodes lastRowID and rowCount to primary key hash header. -func (s *Storage) EncodePKHeader(lastRowID, rowCount uint64) (header common.Hash) { - binary.BigEndian.PutUint64(header[:8], lastRowID) - binary.BigEndian.PutUint64(header[8:16], rowCount) - return +func hasBit(n byte, pos uint) bool { + val := n & (1 << pos) + return (val > 0) } -// UpdateHash updates hash to stateDB. -func (s *Storage) UpdateHash(m map[common.Hash]common.Hash, address common.Address) { - for key, val := range m { - s.SetState(address, key, val) +func getOffset(d common.Hash) (offset []uint64) { + for j, b := range d { + for i := 0; i < 8; i++ { + if hasBit(b, uint(i)) { + offset = append(offset, uint64(j*8+i)) + } + } } + return } -func setBit(n byte, pos uint) byte { - n |= (1 << pos) - return n +// RepeatPK returns primary IDs by table reference. +func (s *Storage) RepeatPK(address common.Address, tableRef schema.TableRef) []uint64 { + hash := s.GetPrimaryPathHash(tableRef) + bm := newBitMap(hash, address, s) + return bm.loadPK() } -func hasBit(n byte, pos uint) bool { - val := n & (1 << pos) - return (val > 0) +// IncreasePK increases the primary ID and return it. +func (s *Storage) IncreasePK( + address common.Address, + tableRef schema.TableRef, +) uint64 { + hash := s.GetPrimaryPathHash(tableRef) + bm := newBitMap(hash, address, s) + return bm.increasePK() } // SetPK sets IDs to primary bit map. -func (s *Storage) SetPK(address common.Address, tableRef schema.TableRef, IDs []uint64) { - hash := s.GetPrimaryPathHash(tableRef) - header := s.GetState(address, hash) - lastRowID, rowCount := s.DecodePKHeader(header) - slotHashToData := make(map[common.Hash]common.Hash) +func (s *Storage) SetPK(address common.Address, headerHash common.Hash, IDs []uint64) { + bm := newBitMap(headerHash, address, s) + bm.setPK(IDs) +} + +type bitMap struct { + storage *Storage + headerSlot common.Hash + headerData common.Hash + address common.Address + dirtySlot map[uint64]common.Hash +} + +func (bm *bitMap) decodeHeader() (lastRowID, rowCount uint64) { + lastRowID = binary.BigEndian.Uint64(bm.headerData[:8]) + rowCount = binary.BigEndian.Uint64(bm.headerData[8:16]) + return +} + +func (bm *bitMap) encodeHeader(lastRowID, rowCount uint64) { + binary.BigEndian.PutUint64(bm.headerData[:8], lastRowID) + binary.BigEndian.PutUint64(bm.headerData[8:16], rowCount) +} + +func (bm *bitMap) increasePK() uint64 { + lastRowID, rowCount := bm.decodeHeader() + lastRowID++ + rowCount++ + bm.encodeHeader(lastRowID, rowCount) + shift := lastRowID/256 + 1 + slot := bm.storage.ShiftHashUint64(bm.headerSlot, shift) + data := bm.storage.GetState(bm.address, slot) + byteShift := (lastRowID & 255) / 8 + data[byteShift] = setBit(data[byteShift], uint(lastRowID&7)) + bm.dirtySlot[shift] = data + bm.flushAll() + return lastRowID +} + +func (bm *bitMap) flushHeader() { + bm.storage.SetState(bm.address, bm.headerSlot, bm.headerData) +} + +func (bm *bitMap) flushAll() { + for k, v := range bm.dirtySlot { + slot := bm.storage.ShiftHashUint64(bm.headerSlot, k) + bm.storage.SetState(bm.address, slot, v) + } + bm.flushHeader() + bm.dirtySlot = make(map[uint64]common.Hash) +} + +func (bm *bitMap) setPK(IDs []uint64) { + lastRowID, rowCount := bm.decodeHeader() for _, id := range IDs { if lastRowID < id { lastRowID = id @@ -578,45 +634,30 @@ func (s *Storage) SetPK(address common.Address, tableRef schema.TableRef, IDs [] slotNum := id/256 + 1 byteLoc := (id & 255) / 8 bitLoc := uint(id & 7) - slotHash := s.ShiftHashUint64(hash, slotNum) - data, exist := slotHashToData[slotHash] + data, exist := bm.dirtySlot[slotNum] if !exist { - data = s.GetState(address, slotHash) + slotHash := bm.storage.ShiftHashUint64(bm.headerSlot, slotNum) + data = bm.storage.GetState(bm.address, slotHash) } if !hasBit(data[byteLoc], bitLoc) { rowCount++ data[byteLoc] = setBit(data[byteLoc], bitLoc) } - slotHashToData[slotHash] = data + bm.dirtySlot[slotNum] = data } - s.UpdateHash(slotHashToData, address) - header = s.EncodePKHeader(lastRowID, rowCount) - s.SetState(address, hash, header) + bm.encodeHeader(lastRowID, rowCount) + bm.flushAll() } -func getCountAndOffset(d common.Hash) (offset []uint64) { - for j, b := range d { - for i := 0; i < 8; i++ { - if hasBit(b, uint(i)) { - offset = append(offset, uint64(j*8+i)) - } - } - } - return -} - -// RepeatPK returns primary IDs by table reference. -func (s *Storage) RepeatPK(address common.Address, tableRef schema.TableRef) []uint64 { - hash := s.GetPrimaryPathHash(tableRef) - header := s.GetState(address, hash) - lastRowID, rowCount := s.DecodePKHeader(header) +func (bm *bitMap) loadPK() []uint64 { + lastRowID, rowCount := bm.decodeHeader() maxSlotNum := lastRowID/256 + 1 result := make([]uint64, rowCount) ptr := 0 for slotNum := uint64(0); slotNum < maxSlotNum; slotNum++ { - slotHash := s.ShiftHashUint64(hash, slotNum+1) - slotData := s.GetState(address, slotHash) - offsets := getCountAndOffset(slotData) + slotHash := bm.storage.ShiftHashUint64(bm.headerSlot, slotNum+1) + slotData := bm.storage.GetState(bm.address, slotHash) + offsets := getOffset(slotData) for i, o := range offsets { result[i+ptr] = o + slotNum*256 } @@ -624,3 +665,9 @@ func (s *Storage) RepeatPK(address common.Address, tableRef schema.TableRef) []u } return result } + +func newBitMap(headerSlot common.Hash, address common.Address, s *Storage) *bitMap { + headerData := s.GetState(address, headerSlot) + bm := bitMap{s, headerSlot, headerData, address, make(map[uint64]common.Hash)} + return &bm +} |