// Initializes the content of a page. func (page *Page) Init(specialSize uintptr) { copy(page.bytes[:], _PageZero) specialSize = system.MaxAlign(specialSize) offsetSpecial := uint16(system.BlockSize - specialSize) page.SetLower(sizeOfPageHeader) page.SetUpper(offsetSpecial) page.SetSpecial(offsetSpecial) page.SetPageSizeAndVersion(system.BlockSize, LayoutVersion) }
func FormHeapTuple(values []system.Datum, tupdesc *TupleDesc) *HeapTuple { natts := len(tupdesc.Attrs) hasnull := false for _, value := range values { if value == nil { hasnull = true //} else if att.attlen == -1 // TODO: flatten toast value } } length := unsafe.Offsetof(HeapTupleHeader{}.bits) if hasnull { length += uintptr(bitmapLength(natts)) } if tupdesc.hasOid { length += unsafe.Sizeof(system.Oid(0)) } length = system.MaxAlign(length) hoff := uint8(length) data_len := computeHeapDataSize(values, tupdesc) length += data_len tuple_data := make([]byte, length) tuple := &HeapTuple{ tupdesc: tupdesc, tableOid: system.InvalidOid, } tuple.SetData(tuple_data, system.InvalidItemPointer) td := tuple.data td.SetNatts(system.AttrNumber(natts)) td.hoff = hoff if tupdesc.hasOid { td.infomask = heapHasOid } bits := []byte(nil) if hasnull { bits = tuple.bytes[unsafe.Offsetof(td.bits):hoff] } data := tuple.bytes[hoff:] td.fill(values, tupdesc, bits, data) return tuple }
func (page *Page) AddItem(item []byte, offset system.OffsetNumber, overwrite, is_heap bool) system.OffsetNumber { // Be wary about corrupted page pointers if page.Lower() < sizeOfPageHeader || page.Lower() > page.Upper() || page.Upper() > page.Special() || page.Special() > system.BlockSize { log.Panicf("corrupted page pointers: lower = %d, upper = %d, special = %d", page.Lower(), page.Upper(), page.Special()) } // Select offset to place the new item at limit := page.MaxOffsetNumber().Next() needshuffle := false // was offset passed in? if offset.IsValid() { // yes, check it if overwrite { if offset < limit { itemId := page.ItemId(offset) if itemId.IsUsed() || itemId.HasStorage() { log.Println("WARNING: will not overwrite a used ItemId") return system.InvalidOffsetNumber } } } else { if offset < limit { // need to move existing linp's needshuffle = true } } } else { if page.HasFreeLinePointers() { for offset = 1; offset < limit; offset = offset.Next() { itemId := page.ItemId(offset) if !itemId.IsUsed() && !itemId.HasStorage() { break } } if offset >= limit { page.ClearHasFreeLinePointers() } } else { // don't bother searching if hint says there's no free slot offset = limit } } if offset > limit { log.Println("WARNING: specified item offset is too large") return system.InvalidOffsetNumber } // if is_heap && offset > MaxHeapTuplesPerPage { // log.Println("WARNING: can't put more than MaxHeapTuplesPerPage items in a heap page") // return InvalidOffsetNumber // } // Compute new lower and upper pointers for page, see if it'll fit. // Note: do arithmetic as signed ints, to avoid mistakes if, say, // alignedSize > upper. lower := int(page.Lower()) if offset == limit || needshuffle { lower = lower + int(unsafe.Sizeof(ItemId(0))) } alignedSize := system.MaxAlign(uintptr(len(item))) upper := int(page.Upper()) - int(alignedSize) if lower > upper { return system.InvalidOffsetNumber } // OK to insert the item. First, shuffle the existing pointers if needed. itemId := page.ItemId(offset) if needshuffle { destItemId := page.ItemId(offset + 1) base := uintptr(unsafe.Pointer(&page.bytes[0])) destStart := uintptr(unsafe.Pointer(destItemId)) - base srcStart := uintptr(unsafe.Pointer(itemId)) - base copyLen := uintptr(limit-offset) * unsafe.Sizeof(ItemId(0)) dest := page.bytes[destStart : destStart+copyLen] src := page.bytes[srcStart : srcStart+copyLen] copy(dest, src) } // set the item pointer itemId.SetNormal(uint(upper), uint(len(item))) // copy the item's data onto the page if l := copy(page.bytes[upper:], item); l != len(item) { panic("unexpected copy result") } page.SetLower(uint16(lower)) page.SetUpper(uint16(upper)) return offset }