public NewUnusedSegment allocateNewSegment(LayerWriteGroup tx, int length) { // use one big nasty lock to prevent race conditions lock (this) { // try to find an extent with enough space to carve off a chunk foreach (var rec in store.scanForward(new ScanRange<RecordKey>(freelist_prefix, RecordKey.AfterPrefix(freelist_prefix), null))) { FreespaceExtent extent = FreespaceExtent.unpack(rec.Value.data); if (extent.length() == length) { // the extent is exactly the right size... make it pending LayerWriteGroup makepending_wg = tx.mylayer.newWriteGroup(type: LayerWriteGroup.WriteGroupType.DISK_ATOMIC_NOFLUSH); // add a pending entry for this block { RecordKey key = new RecordKey().appendParsedKey(".ROOT/FREELIST/PENDING"); key.appendKeyPart(new RecordKeyType_Long(extent.start_addr)); makepending_wg.setValue(key, RecordUpdate.WithPayload(extent.pack())); } // remove the freelist entry { RecordKey key = new RecordKey().appendParsedKey(".ROOT/FREELIST/EXTENTS"); key.appendKeyPart(new RecordKeyType_Long(extent.end_addr)); makepending_wg.setValue(key, RecordUpdate.DeletionTombstone()); } makepending_wg.finish(); return new NewUnusedSegment(store, extent); } else if (extent.length() > length) { // TODO: carve a piece off the extent and return the pending piece } } // if we can't find a free segment, grow the heap return growHeap(tx, length); // TODO: then carve a segment out of the new grown heap } }
public void mapSegment(LayerWriteGroup tx, int use_gen, RecordKey start_key, RecordKey end_key, IRegion reader) { if (! (tx.type == LayerWriteGroup.WriteGroupType.DISK_ATOMIC_NOFLUSH || tx.type == LayerWriteGroup.WriteGroupType.DISK_ATOMIC_FLUSH)) { throw new Exception("NewUnusedSegment.mapSegment() must be provided an ATOMIC write group"); } // remove the pending entry RecordKey key = new RecordKey().appendParsedKey(".ROOT/FREELIST/PENDING"); key.appendKeyPart(new RecordKeyType_Long(reader.getStartAddress())); tx.setValue(key, RecordUpdate.DeletionTombstone()); // add the new map tx.mylayer.rangemapmgr.mapGenerationToRegion(tx, use_gen, start_key, end_key, reader); }
// grow the top "top of heap" // .ROOT/FREELIST/HEAD -> "top of heap" private NewUnusedSegment growHeap(LayerWriteGroup tx, int length) { long new_addr; FreespaceExtent newblock_info; // make an atomic write-group to "carve off" a pending chunk LayerWriteGroup carveoff_wg = tx.mylayer.newWriteGroup(type: LayerWriteGroup.WriteGroupType.DISK_ATOMIC_NOFLUSH); // lock to make sure two threads don't carve off at the same time... lock (this) { // HACK: currently we just grab off the top of heap new_addr = next_allocation; next_allocation = next_allocation + (long)length; if (new_addr <= 0) { throw new Exception("invalid address in allocateNewSegment: " + new_addr); } newblock_info = new FreespaceExtent(); newblock_info.start_addr = new_addr; newblock_info.end_addr = new_addr + length; // add the pending chunk carveoff_wg.setValue(this.pendingKeyForAddr(new_addr), RecordUpdate.WithPayload(newblock_info.pack())); Console.WriteLine("allocateNewSegment - next address: " + new_addr); // add our new top of heap pointer { RecordKey key = new RecordKey().appendParsedKey(".ROOT/FREELIST/HEAD"); carveoff_wg.setValue(key, RecordUpdate.WithPayload(Lsd.numberToLsd(next_allocation, 13))); } // commit the metadata tx carveoff_wg.finish(); } return new NewUnusedSegment(store,newblock_info); }
// move the pending address into the freelist private void handleRegionSafeToFree(long start_addr, FreespaceExtent extent, LayerWriteGroup wg) { System.Console.WriteLine("*\n*\n*\n* handleRegionSafeToFree {0} \n*\n*\n*", start_addr); // (1) remove pending entry wg.setValue(pendingKeyForAddr(start_addr), RecordUpdate.DeletionTombstone()); // (2) write real freelist entry (TODO: merge with neighboring entries) { RecordKey key = new RecordKey().appendParsedKey(".ROOT/FREELIST/EXTENTS"); key.appendKeyPart(new RecordKeyType_Long(extent.end_addr)); wg.setValue(key, RecordUpdate.WithPayload(extent.pack())); } wg.finish(); }
public void freeSegment(LayerWriteGroup tx, FreespaceExtent segment_extent) { // (1) add the segment to the pending list (pending free) if (tx.type != LayerWriteGroup.WriteGroupType.DISK_ATOMIC_FLUSH) { throw new Exception("freeSegment() requires DISK_ATOMIC write group"); } // NOTE: DISK_ATOMIC writes are not seen in the memory segment until the atomic write group applies // so these changes will not be seen until then RecordKey key = new RecordKey().appendParsedKey(".ROOT/FREELIST/PENDING") .appendKeyPart(new RecordKeyType_Long(segment_extent.end_addr)); RecordUpdate payload = RecordUpdate.WithPayload(segment_extent.pack()); tx.setValue(key, payload); // (2) add a handler to get notified when the block is no longer referenced, so it can // be moved from pending to actually free. LayerWriteGroup fwg = this.store.newWriteGroup(LayerWriteGroup.WriteGroupType.DISK_ATOMIC_NOFLUSH); // we don't want to ask for the notification until the write-group freeing this segment is finished tx.addCompletion(delegate() { tx.mylayer.regionmgr.notifyRegionSafeToFree(segment_extent.start_addr, delegate(long addr) { this.handleRegionSafeToFree(addr, segment_extent, fwg); }); }); }