• Mindscape ๐Ÿ”ฅ
    • Playlist ๐ŸŽง
  • Algorithm

    • 1018๋ฒˆ: ์ฒด์ŠคํŒ ๋‹ค์‹œ ์น ํ•˜๊ธฐ
    • 1966๋ฒˆ: ํ”„๋ฆฐํ„ฐ ํ
    • Python ์‹œ๊ฐ„ ์ดˆ๊ณผ ๋ฐฉ์ง€๋ฅผ ์œ„ํ•œ ํŒ
    • C++ std::vector ์‚ฌ์šฉ๋ฒ• ์ •๋ฆฌ
    • Vim ์‚ฌ์šฉ ๋งค๋‰ด์–ผ
  • Ubuntu

    • ๋ฆฌ๋ˆ…์Šค ์šฐ๋ถ„ํˆฌ GRUB ํฐํŠธ ๋ณ€๊ฒฝ
    • ์šฐ๋ถ„ํˆฌ ์ด๋ฏธ์ง€ ๋น„๋””์˜ค ์ธ๋„ค์ผ(๋ฏธ๋ฆฌ๋ณด๊ธฐ) ์•ˆ ๋ณด์ž„ ๋ฌธ์ œ ํ•ด๊ฒฐ
    • Wine ํ™˜๊ฒฝ์—์„œ ์นด์นด์˜คํ†ก ์‹คํ–‰ ์‹œ explorer.exe ๋œจ์ง€ ์•Š๊ฒŒ ํ•˜๋Š” ๋ฒ•
    • ์šฐ๋ถ„ํˆฌ Wine ์นด์นด์˜คํ†ก ์‚ฌ์ง„ ์ด๋ฏธ์ง€ ์Šคํฌ๋ฆฐ์ƒท ๋ถ™์—ฌ๋„ฃ๊ธฐ
    • Wine ์นด์นด์˜คํ†ก ์ด๋ชจ์ง€ ๊นจ์ง ๋ฌธ์ œ ํ•ด๊ฒฐ
    • Ubuntu ์œˆ๋„์šฐ ์• ๋‹ˆ๋ฉ”์ด์…˜ ๋„๊ธฐ
  • Wellness

    • ์ฐจ์ „์žํ”ผ (Psyllium Husk)
    • ์—‘์ŠคํŠธ๋ผ ๋ฒ„์ง„ ์˜ฌ๋ฆฌ๋ธŒ์œ  (Extra Virgin Olive Oil)
    • ์ž๊ฐ€๋น„๊ฐ•์„ธ์ฒ™ (Nasal Irrigation)
    • QCY HT08 (MeloBuds Pro Plus)
    • ์ฝ˜์„œํƒ€ (Concerta)
    • ์ธ๋ฐ๋†€ (Inderal)
    • ์„คํŠธ๋ž„๋ฆฐ (Sertraline)
    • ๋ฉœ๋ผํ† ๋‹Œ (Melatonin)
    • ์น˜๊ฒฝ๋ถ€ ๋งˆ๋ชจ์ฆ
    • ๋ฐ”๋ฒจ ์Šค์ฟผํŠธ (Barbell Squat)
  • Humanities

    • Nordvik, Russia
    • North Sentinel Island
    • ๋กฑ๊ณ ๋กฑ๊ณ (Rongorongo)
    • ๋ฐ”๋กœํฌ ์Œ์•… (Baroque Music)
  • Design

    • ๊ตฌ๊ธ€์˜ ์•„์ด์ฝ˜ ๋Œ€๊ฐœํŽธ โ€” 6๋…„ ๋งŒ์˜ ์‹ค์ˆ˜ ์ธ์ •
    • ์ œ๋Ÿด๋“œ ์  ํƒ€ โ€” ๋Ÿญ์…”๋ฆฌ ์Šคํฌ์ธ  ์›Œ์น˜์˜ ์ฐฝ์‹œ์ž
    • ๋ฐ”์šฐํ•˜์šฐ์Šค โ€” ํ˜„๋Œ€ ๋””์ž์ธ์˜ ์›์ 
  • Brands

    • NOMOS Glashรผtte
    • Frรฉdรฉrique Constant
    • KZ (Knowledge Zenith)
    • ์—์ŠคํŠธ๋ผ (AESTURA)
    • JINHAO (้‡‘่ฑช)
    • Herman Miller
    • ๋ฐ์Šค์ปค (DESKER)
    • ๋ฌด์‹ ์‚ฌ ์Šคํƒ ๋‹ค๋“œ (Musinsa Standard)
  • Finance

    • ํ˜„๋Œ€์นด๋“œ ZERO โ€” Edition2 vs Edition3 ๋น„๊ต
    • ์‹ ํ•œ์นด๋“œ ์ฒ˜์Œ
    • S&P 500 ETF ํˆฌ์ž ๊ฐ€์ด๋“œ
    • ํŒŒํ‚นํ†ต์žฅ vs CMA ํ†ต์žฅ
    • ๋ฒ„ํฌ์…” ํ•ด์„œ์›จ์ด (Berkshire Hathaway)
    • ๋น„ํŠธ์ฝ”์ธ(Bitcoin)
  • Products

    • ์˜ค๋””์˜ค ์ธํ„ฐํŽ˜์ด์Šค (Audio Interface)
    • ์ฟ ๋ฃจํ† ๊ฐ€ (KURUTOGA)
    • CX31993 DAC ๋™๊ธ€
    • ํด๋ Œ์ง• ๋ฐ€ํฌ (Cleansing Milk)
    • ํ”ผ์ ฏ ํ† ์ด (Fidget Toy)
    • ThinkPad
  • Programming Languages

    • 8.0. Statement Level Control Structures
    • 8. Subprogram
    • 9. Implementing Subprogram
    • 10.1. Abstract Data Types and Encapsulation Constructs
    • 10.2. Support for Object Oriented Programming
    • 11. Concurrency
    • 12. FPL (1)
    • 13. FPL (2)
    • 14. Exception Handling and Event Handling
    • Final Exam
// bptree1/src/bpt.c

#include "bpt.h"

H_P * hp;
page * rt = NULL; 
int fd = -1; 

// --- File I/O & Page Management ---

H_P * load_header(off_t off) {
    H_P * newhp = (H_P*)calloc(1, sizeof(H_P));
    if (sizeof(H_P) > pread(fd, newhp, sizeof(H_P), 0)) {
        free(newhp);
        return NULL;
    }
    return newhp;
}

page * load_page(off_t off) {
    page* load = (page*)calloc(1, sizeof(page));
    if (sizeof(page) > pread(fd, load, sizeof(page), off)) {
        free(load);
        return NULL;
    }
    return load;
}

int open_table(char * pathname) {
    // 1. ํŒŒ์ผ ์ƒ์„ฑ ์‹œ๋„ (์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ)
    fd = open(pathname, O_RDWR | O_CREAT | O_EXCL | O_SYNC, 0775);
    hp = (H_P *)calloc(1, sizeof(H_P));
    
    if (fd > 0) {
        hp->fpo = 0;
        hp->num_of_pages = 1;
        hp->rpo = 0;
        pwrite(fd, hp, sizeof(H_P), 0);
        free(hp);
        hp = load_header(0);
        return 0;
    }
    
    // 2. ๊ธฐ์กด ํŒŒ์ผ ์—ด๊ธฐ
    fd = open(pathname, O_RDWR | O_SYNC);
    if (fd > 0) {
        if (sizeof(H_P) > pread(fd, hp, sizeof(H_P), 0)) {
            free(hp);
            return -1;
        }
        if (hp->rpo != 0) {
            rt = load_page(hp->rpo);
        }
        return 0;
    }
    
    free(hp);
    return -1;
}

// ์ƒˆ ํŽ˜์ด์ง€ ํ• ๋‹น (Free List ์žฌ์‚ฌ์šฉ ๋˜๋Š” ํŒŒ์ผ ํ™•์žฅ)
off_t new_page() {
    off_t newp;
    page * np;
    
    // 1. Free Page ์žฌ์‚ฌ์šฉ
    if (hp->fpo != 0) {
        newp = hp->fpo;
        np = load_page(newp);
        hp->fpo = np->parent_page_offset; // Free List Head ๊ฐฑ์‹ 
        pwrite(fd, hp, sizeof(H_P), 0);
        free(hp);
        hp = load_header(0);
        free(np);
        freetouse(newp); // ํŽ˜์ด์ง€ ๋‚ด์šฉ ์ดˆ๊ธฐํ™”
        return newp;
    }
    
    // 2. ํŒŒ์ผ ๋(EOF) ํ™•์žฅ
    newp = lseek(fd, 0, SEEK_END);
    reset(newp); // ํŽ˜์ด์ง€ ์ดˆ๊ธฐํ™”
    hp->num_of_pages++;
    pwrite(fd, hp, sizeof(H_P), 0);
    free(hp);
    hp = load_header(0);
    return newp;
}

// ํŽ˜์ด์ง€ ์ดˆ๊ธฐํ™” (0์œผ๋กœ ์ฑ„์›€)
void reset(off_t off) {
    page * reset = (page*)calloc(1, sizeof(page));
    pwrite(fd, reset, sizeof(page), off);
    free(reset);
}

// ํŽ˜์ด์ง€ ์ดˆ๊ธฐํ™” (Free List์—์„œ ๊บผ๋‚ผ ๋•Œ)
void freetouse(off_t fpo) {
    page * reset = load_page(fpo);
    reset->parent_page_offset = 0;
    reset->is_leaf = 0;
    reset->num_of_keys = 0;
    reset->next_offset = 0;
    pwrite(fd, reset, sizeof(page), fpo);
    free(reset);
}

// ํŽ˜์ด์ง€ ๋ฐ˜๋‚ฉ (Free List์— ์ถ”๊ฐ€)
void usetofree(off_t wbf) {
    page * utf = load_page(wbf);
    utf->parent_page_offset = hp->fpo; // ๊ธฐ์กด Head๋ฅผ ๊ฐ€๋ฆฌํ‚ด
    utf->is_leaf = 0;
    utf->num_of_keys = 0;
    utf->next_offset = 0;
    pwrite(fd, utf, sizeof(page), wbf);
    free(utf);
    
    hp->fpo = wbf; // Head ๊ฐฑ์‹ 
    pwrite(fd, hp, sizeof(H_P), 0);
    free(hp);
    hp = load_header(0);
}

int cut(int length) {
    if (length % 2 == 0) return length / 2;
    else return length / 2 + 1;
}

// ์ƒˆ DB ํŒŒ์ผ ์‹œ์ž‘ (Root ์ƒ์„ฑ)
void start_new_file(record rec) {
    off_t ro = new_page();
    hp->rpo = ro;
    pwrite(fd, hp, sizeof(H_P), 0);
    free(hp);
    hp = load_header(0);

    rt = load_page(ro);
    rt->num_of_keys = 1;
    rt->is_leaf = 1;
    rt->parent_page_offset = 0;
    rt->records[0] = rec;
    pwrite(fd, rt, sizeof(page), hp->rpo);
    free(rt);
    rt = load_page(hp->rpo);
}

// --- Find Operation ---

// Key๊ฐ€ ์œ„์น˜ํ•œ Leaf Page ํƒ์ƒ‰
off_t find_leaf(int64_t key) {
    if (hp->rpo == 0) return 0;
    
    off_t current_offset = hp->rpo;
    page* p = NULL;
    
    while (current_offset != 0) {
        p = load_page(current_offset);
        if (p == NULL) return 0;

        if (p->is_leaf) {
            free(p);
            return current_offset;
        } else {
            int i = 0;
            while (i < p->num_of_keys && key >= p->b_f[i].key) {
                i++;
            }
            // ์™ผ์ชฝ ํฌ์ธํ„ฐ ๊ฒฐ์ • (one more page vs b_f[i])
            if (i == 0) current_offset = p->next_offset;
            else current_offset = p->b_f[i - 1].p_offset;
            free(p);
        }
    }
    return 0;
}

// Find API
char * db_find(int64_t key) {
    off_t leaf_offset = find_leaf(key);
    if (leaf_offset == 0) return NULL;
    
    page* p = load_page(leaf_offset);
    if (p == NULL) return NULL;

    for (int i = 0; i < p->num_of_keys; i++) {
        if (p->records[i].key == key) {
            char* ret_val = (char*)calloc(1, 120);
            if (ret_val == NULL) { free(p); return NULL; }
            memcpy(ret_val, p->records[i].value, 120);
            free(p);
            return ret_val;
        }
    }
    free(p);
    return NULL;
}

// --- Insert Operation ---

// Leaf Page์— ๋‹จ์ˆœ ์‚ฝ์ž… (๊ณต๊ฐ„ ์žˆ์Œ)
int insert_into_leaf(off_t leaf_offset, record rec) {
    page* p = load_page(leaf_offset);
    if (p == NULL) return -1;

    int i = 0;
    while (i < p->num_of_keys && p->records[i].key < rec.key) {
        i++;
    }
    
    for (int j = p->num_of_keys; j > i; j--) {
        p->records[j] = p->records[j - 1];
    }
    
    p->records[i] = rec;
    p->num_of_keys++;
    pwrite(fd, p, sizeof(page), leaf_offset);
    free(p);
    return 0;
}

// Leaf Page ๋ถ„ํ•  ํ›„ ์‚ฝ์ž…
int insert_into_leaf_after_splitting(off_t leaf_offset, record rec) {
    off_t new_leaf_offset = new_page();
    page* old_leaf = load_page(leaf_offset);
    page* new_leaf = load_page(new_leaf_offset);
    new_leaf->is_leaf = 1;

    // 1. ์ž„์‹œ ๋ฒ„ํผ์— ์ •๋ ฌํ•˜์—ฌ ์‚ฝ์ž…
    record temp_records[LEAF_MAX + 1];
    int i = 0, j = 0;
    while (i < LEAF_MAX && old_leaf->records[i].key < rec.key) {
        temp_records[i] = old_leaf->records[i];
        i++;
    }
    temp_records[i] = rec;
    for (j = i + 1; j <= LEAF_MAX; j++) {
        temp_records[j] = old_leaf->records[j - 1];
    }

    // 2. ๋ถ„ํ•  (Split)
    int split = cut(LEAF_MAX + 1);
    
    // 3. Old Page ๊ฐฑ์‹ 
    old_leaf->num_of_keys = split;
    for (i = 0; i < split; i++) {
        old_leaf->records[i] = temp_records[i];
    }
    
    // 4. New Page ๊ฐฑ์‹ 
    new_leaf->num_of_keys = (LEAF_MAX + 1) - split;
    j = 0;
    for (i = split; i <= LEAF_MAX; i++) {
        new_leaf->records[j++] = temp_records[i];
    }
    
    // 5. Link ์—ฐ๊ฒฐ (Old -> New)
    new_leaf->next_offset = old_leaf->next_offset;
    old_leaf->next_offset = new_leaf_offset;
    new_leaf->parent_page_offset = old_leaf->parent_page_offset;

    pwrite(fd, old_leaf, sizeof(page), leaf_offset);
    pwrite(fd, new_leaf, sizeof(page), new_leaf_offset);
    free(old_leaf);
    free(new_leaf);

    // 6. ๋ถ€๋ชจ์— New Page Key ์‚ฝ์ž…
    new_leaf = load_page(new_leaf_offset);
    int64_t new_key = new_leaf->records[0].key;
    free(new_leaf);
    
    return insert_into_parent(leaf_offset, new_key, new_leaf_offset);
}

// Internal Page ๋‹จ์ˆœ ์‚ฝ์ž…
int insert_into_internal(off_t parent_po, int left_index, int64_t key, off_t right_po) {
    page* parent = load_page(parent_po);
    
    for (int i = parent->num_of_keys; i > left_index + 1; i--) {
        parent->b_f[i] = parent->b_f[i - 1];
    }
    
    parent->b_f[left_index + 1].key = key;
    parent->b_f[left_index + 1].p_offset = right_po;
    parent->num_of_keys++;
    
    pwrite(fd, parent, sizeof(page), parent_po);
    free(parent);
    return 0;
}

// Internal Page ๋ถ„ํ•  ํ›„ ์‚ฝ์ž…
int insert_into_internal_after_splitting(off_t old_page_po, int left_index, int64_t key, off_t right_po) {
    I_R temp_entries[INTERNAL_MAX + 1];
    page* old_page = load_page(old_page_po);
    off_t temp_first_po = old_page->next_offset;
    
    // 1. ์ž„์‹œ ๋ฒ„ํผ์— ์ •๋ ฌ ๋ฐ ์‚ฝ์ž…
    int i = 0, j = 0;
    for (i = 0; i < left_index + 1; i++) temp_entries[i] = old_page->b_f[i];
    temp_entries[i].key = key;
    temp_entries[i].p_offset = right_po;
    for (j = i + 1; j <= INTERNAL_MAX; j++) temp_entries[j] = old_page->b_f[j - 1];

    // 2. ๋ถ„ํ•  ๋ฐ K_prime(๋ถ€๋ชจ๋กœ ์˜ฌ๋ฆด ํ‚ค) ์„ ์ •
    int split_index = cut(INTERNAL_MAX + 1);
    int64_t k_prime = temp_entries[split_index].key;

    // 3. Old Page ๊ฐฑ์‹ 
    old_page->num_of_keys = split_index;
    old_page->next_offset = temp_first_po;
    for (i = 0; i < split_index; i++) old_page->b_f[i] = temp_entries[i];

    // 4. New Page ์ƒ์„ฑ ๋ฐ ๊ฐฑ์‹ 
    off_t new_page_po = new_page();
    page* new_page = load_page(new_page_po);
    new_page->is_leaf = 0;
    new_page->next_offset = temp_entries[split_index].p_offset; // K_prime์˜ ์˜ค๋ฅธ์ชฝ ์ž์‹์ด New Page์˜ ์ฒซ ํฌ์ธํ„ฐ
    new_page->num_of_keys = (INTERNAL_MAX + 1) - (split_index + 1);
    
    j = 0;
    for (i = split_index + 1; i <= INTERNAL_MAX; i++) new_page->b_f[j++] = temp_entries[i];

    // 5. ์ž์‹๋“ค์˜ ๋ถ€๋ชจ ํฌ์ธํ„ฐ ๊ฐฑ์‹ 
    page* child = load_page(new_page->next_offset);
    child->parent_page_offset = new_page_po;
    pwrite(fd, child, sizeof(page), new_page->next_offset);
    free(child);
    
    for (i = 0; i < new_page->num_of_keys; i++) {
        child = load_page(new_page->b_f[i].p_offset);
        child->parent_page_offset = new_page_po;
        pwrite(fd, child, sizeof(page), new_page->b_f[i].p_offset);
        free(child);
    }

    new_page->parent_page_offset = old_page->parent_page_offset;
    pwrite(fd, old_page, sizeof(page), old_page_po);
    pwrite(fd, new_page, sizeof(page), new_page_po);
    free(old_page);
    free(new_page);

    return insert_into_parent(old_page_po, k_prime, new_page_po);
}

// ๋ถ€๋ชจ์— Key ์‚ฝ์ž… (์žฌ๊ท€)
int insert_into_parent(off_t left_po, int64_t key, off_t right_po) {
    page* left = load_page(left_po);
    off_t parent_po = left->parent_page_offset;
    free(left);

    // Case 1: ๋ถ€๋ชจ ์—†์Œ (์ƒˆ Root ์ƒ์„ฑ)
    if (parent_po == 0) {
        insert_into_new_root(left_po, key, right_po);
        return 0;
    }

    // Case 2: ๋ถ€๋ชจ ์กด์žฌ
    int left_index = get_left_index(parent_po, left_po);
    page* parent = load_page(parent_po);

    if (parent->num_of_keys < INTERNAL_MAX) {
        free(parent);
        return insert_into_internal(parent_po, left_index, key, right_po);
    } else {
        free(parent);
        return insert_into_internal_after_splitting(parent_po, left_index, key, right_po);
    }
}

void insert_into_new_root(off_t left_po, int64_t key, off_t right_po) {
    off_t root_po = new_page();
    page* root = load_page(root_po);
    page* left = load_page(left_po);
    page* right = load_page(right_po);

    root->num_of_keys = 1;
    root->is_leaf = 0;
    root->parent_page_offset = 0;
    root->next_offset = left_po;
    root->b_f[0].key = key;
    root->b_f[0].p_offset = right_po;

    left->parent_page_offset = root_po;
    right->parent_page_offset = root_po;

    pwrite(fd, root, sizeof(page), root_po);
    pwrite(fd, left, sizeof(page), left_po);
    pwrite(fd, right, sizeof(page), right_po);

    hp->rpo = root_po;
    pwrite(fd, hp, sizeof(H_P), 0);
    free(hp);
    hp = load_header(0);
    free(root); free(left); free(right);
}

// Insert API
int db_insert(int64_t key, char * value) {
    char* find_result = db_find(key);
    if (find_result != NULL) {
        free(find_result);
        return -1; // ์ค‘๋ณต ํ‚ค
    }

    record new_record;
    new_record.key = key;
    strncpy(new_record.value, value, 120);

    if (hp->rpo == 0) {
        start_new_file(new_record);
        return 0;
    }

    off_t leaf_offset = find_leaf(key);
    page* leaf_page = load_page(leaf_offset);

    if (leaf_page->num_of_keys < LEAF_MAX) {
        free(leaf_page);
        return insert_into_leaf(leaf_offset, new_record);
    } else {
        free(leaf_page);
        return insert_into_leaf_after_splitting(leaf_offset, new_record);
    }
}

// --- Delete Operation ---

// ์™ผ์ชฝ ํ˜•์ œ ์ธ๋ฑ์Šค ์ฐพ๊ธฐ
int get_neighbor_index(off_t page_offset, off_t parent_offset) {
    page* parent = load_page(parent_offset);
    int i = 0;
    
    if (parent->next_offset == page_offset) {
        free(parent); return -2; // ์™ผ์ชฝ ํ˜•์ œ ์—†์Œ (์ž์‹ ์ด ์ฒซ์งธ)
    }
    if (parent->num_of_keys > 0 && parent->b_f[0].p_offset == page_offset) {
        free(parent); return -1; // ์™ผ์ชฝ ํ˜•์ œ๊ฐ€ one-more-page
    }
    for (i = 1; i < parent->num_of_keys; i++) {
        if (parent->b_f[i].p_offset == page_offset) {
            free(parent); return i - 1;
        }
    }
    free(parent); return -3;
}

int get_left_index(off_t parent_po, off_t left_po) {
    page* parent = load_page(parent_po);
    if (parent->next_offset == left_po) { free(parent); return -1; }
    for (int i = 0; i < parent->num_of_keys; i++) {
        if (parent->b_f[i].p_offset == left_po) { free(parent); return i; }
    }
    free(parent); return -2;
}

// ๋ฌผ๋ฆฌ์  ๋ ˆ์ฝ”๋“œ ์‚ญ์ œ (Leaf)
void remove_record_from_leaf(off_t leaf_po, int64_t key) {
    page* leaf = load_page(leaf_po);
    int i = 0;
    while (leaf->records[i].key != key) i++;
    
    for (int j = i; j < leaf->num_of_keys - 1; j++) {
        leaf->records[j] = leaf->records[j + 1];
    }
    leaf->num_of_keys--;
    pwrite(fd, leaf, sizeof(page), leaf_po);
    free(leaf);
}

// ๋ฌผ๋ฆฌ์  ํ‚ค ์‚ญ์ œ (Internal)
void remove_entry_from_internal(off_t internal_po, int64_t key) {
    page* p = load_page(internal_po);
    int i = 0;
    while (p->b_f[i].key != key) i++;
    
    for (int j = i; j < p->num_of_keys - 1; j++) {
        p->b_f[j] = p->b_f[j + 1];
    }
    p->num_of_keys--;
    pwrite(fd, p, sizeof(page), internal_po);
    free(p);
}

// Root ์กฐ์ •
void adjust_root(off_t root_po) {
    page* root = load_page(root_po);
    
    // Root๊ฐ€ ๋น„์—ˆ๊ณ  Internal์ธ ๊ฒฝ์šฐ -> ์ž์‹์„ ์ƒˆ Root๋กœ ์Šน๊ฒฉ
    if (root->num_of_keys == 0 && !root->is_leaf) {
        hp->rpo = root->next_offset;
        page* new_root = load_page(hp->rpo);
        new_root->parent_page_offset = 0;
        pwrite(fd, new_root, sizeof(page), hp->rpo);
        free(new_root);
        
        pwrite(fd, hp, sizeof(H_P), 0);
        free(hp);
        hp = load_header(0);
        usetofree(root_po);
    }
    // Root๊ฐ€ ๋น„์—ˆ๊ณ  Leaf์ธ ๊ฒฝ์šฐ -> ํŠธ๋ฆฌ ์‚ญ์ œ
    else if (root->num_of_keys == 0 && root->is_leaf) {
        hp->rpo = 0;
        pwrite(fd, hp, sizeof(H_P), 0);
        free(hp);
        hp = load_header(0);
        usetofree(root_po);
    }
    free(root);
}

// ์žฌ๋ถ„๋ฐฐ (Redistribute)
void redistribute_nodes(off_t neighbor_po, off_t page_po, int neighbor_index, int k_prime_index, int64_t k_prime) {
    page* neighbor = load_page(neighbor_po);
    page* p = load_page(page_po);
    page* parent = load_page(p->parent_page_offset);

    // Case 1: Neighbor๊ฐ€ ์™ผ์ชฝ (Borrow from Left)
    if (neighbor_index != -2) {
        if (!p->is_leaf) {
            for (int i = p->num_of_keys; i > 0; i--) p->b_f[i] = p->b_f[i - 1];
            p->b_f[0].key = k_prime;
            p->b_f[0].p_offset = p->next_offset;
            p->next_offset = neighbor->b_f[neighbor->num_of_keys - 1].p_offset;
            
            page* child = load_page(p->next_offset);
            child->parent_page_offset = page_po;
            pwrite(fd, child, sizeof(page), p->next_offset);
            free(child);
            
            parent->b_f[k_prime_index].key = neighbor->b_f[neighbor->num_of_keys - 1].key;
        } else {
            for (int i = p->num_of_keys; i > 0; i--) p->records[i] = p->records[i - 1];
            p->records[0] = neighbor->records[neighbor->num_of_keys - 1];
            parent->b_f[k_prime_index].key = p->records[0].key;
        }
    }
    // Case 2: Neighbor๊ฐ€ ์˜ค๋ฅธ์ชฝ (Borrow from Right)
    else {
        if (!p->is_leaf) {
            p->b_f[p->num_of_keys].key = k_prime;
            p->b_f[p->num_of_keys].p_offset = neighbor->next_offset;
            
            page* child = load_page(neighbor->next_offset);
            child->parent_page_offset = page_po;
            pwrite(fd, child, sizeof(page), neighbor->next_offset);
            free(child);
            
            parent->b_f[k_prime_index].key = neighbor->b_f[0].key;
            neighbor->next_offset = neighbor->b_f[0].p_offset;
            for (int i = 0; i < neighbor->num_of_keys - 1; i++) neighbor->b_f[i] = neighbor->b_f[i + 1];
        } else {
            p->records[p->num_of_keys] = neighbor->records[0];
            parent->b_f[k_prime_index].key = neighbor->records[1].key;
            for (int i = 0; i < neighbor->num_of_keys - 1; i++) neighbor->records[i] = neighbor->records[i + 1];
        }
    }

    neighbor->num_of_keys--;
    p->num_of_keys++;
    
    pwrite(fd, parent, sizeof(page), p->parent_page_offset);
    pwrite(fd, p, sizeof(page), page_po);
    pwrite(fd, neighbor, sizeof(page), neighbor_po);
    
    free(parent); free(p); free(neighbor);
}

// ๋ณ‘ํ•ฉ (Coalesce)
void coalesce_nodes(off_t neighbor_po, off_t page_po, int neighbor_index, int k_prime_index, int64_t k_prime) {
    page* neighbor = load_page(neighbor_po);
    page* p = load_page(page_po);
    page* parent = load_page(p->parent_page_offset);

    // Swap (ํ•ญ์ƒ p๋ฅผ neighbor๋กœ ํ•ฉ์น˜๊ธฐ ์œ„ํ•ด)
    if (neighbor_index == -2) {
        page* tmp = p; p = neighbor; neighbor = tmp;
        off_t tmp_off = page_po; page_po = neighbor_po; neighbor_po = tmp_off;
    }

    // 1. ๋‚ด์šฉ ๋ณ‘ํ•ฉ
    if (!p->is_leaf) {
        neighbor->b_f[neighbor->num_of_keys].key = k_prime;
        neighbor->b_f[neighbor->num_of_keys].p_offset = p->next_offset;
        neighbor->num_of_keys++;

        for (int i = 0; i < p->num_of_keys; i++) {
            neighbor->b_f[neighbor->num_of_keys] = p->b_f[i];
            neighbor->num_of_keys++;
        }
        
        // ์ž์‹๋“ค์˜ ๋ถ€๋ชจ ๋ณ€๊ฒฝ
        page* child = load_page(p->next_offset);
        child->parent_page_offset = neighbor_po;
        pwrite(fd, child, sizeof(page), p->next_offset);
        free(child);
        for (int i = 0; i < p->num_of_keys; i++) {
            child = load_page(p->b_f[i].p_offset);
            child->parent_page_offset = neighbor_po;
            pwrite(fd, child, sizeof(page), p->b_f[i].p_offset);
            free(child);
        }
    } else {
        for (int i = 0; i < p->num_of_keys; i++) {
            neighbor->records[neighbor->num_of_keys] = p->records[i];
            neighbor->num_of_keys++;
        }
        neighbor->next_offset = p->next_offset;
    }

    pwrite(fd, neighbor, sizeof(page), neighbor_po);
    usetofree(page_po);
    
    // 2. ๋ถ€๋ชจ์—์„œ Key ์‚ญ์ œ (์žฌ๊ท€)
    delete_entry(p->parent_page_offset, k_prime);
    
    free(parent); free(p); free(neighbor);
}

// ์—”ํŠธ๋ฆฌ ์‚ญ์ œ (์žฌ๊ท€ ํ˜ธ์ถœ์˜ ํ•ต์‹ฌ)
int delete_entry(off_t page_offset, int64_t key) {
    // 1. ๋ฌผ๋ฆฌ์  ์‚ญ์ œ
    page* p = load_page(page_offset);
    if (p->is_leaf) remove_record_from_leaf(page_offset, key);
    else remove_entry_from_internal(page_offset, key);

    // 2. Root ์ฒดํฌ
    if (page_offset == hp->rpo) {
        adjust_root(page_offset);
        free(p);
        return 0;
    }

    // 3. Underflow ์ฒดํฌ
    int min_keys = p->is_leaf ? cut(LEAF_MAX + 1) - 1 : cut(INTERNAL_MAX + 1) - 1;
    free(p); p = load_page(page_offset); // Refresh
    if (p->num_of_keys >= min_keys) {
        free(p); return 0;
    }

    // 4. Underflow ๋ฐœ์ƒ: Neighbor & K_prime ์ฐพ๊ธฐ
    off_t parent_po = p->parent_page_offset;
    page* parent = load_page(parent_po);
    int neighbor_index = get_neighbor_index(page_offset, parent_po);
    int k_prime_index = (neighbor_index == -2) ? 0 : neighbor_index + 1;
    int64_t k_prime = parent->b_f[k_prime_index].key;
    
    off_t neighbor_po = (neighbor_index == -2) ? parent->b_f[0].p_offset : 
                        (neighbor_index == -1) ? parent->next_offset : 
                        parent->b_f[neighbor_index].p_offset;
    
    page* neighbor = load_page(neighbor_po);

    // 5. ์žฌ๋ถ„๋ฐฐ ๋˜๋Š” ๋ณ‘ํ•ฉ
    if (neighbor->num_of_keys > min_keys) {
        redistribute_nodes(neighbor_po, page_offset, neighbor_index, k_prime_index, k_prime);
    } else {
        coalesce_nodes(neighbor_po, page_offset, neighbor_index, k_prime_index, k_prime);
    }

    free(p); free(parent); free(neighbor);
    return 0;
}

// Delete API
int db_delete(int64_t key) {
    off_t leaf_offset = find_leaf(key);
    if (leaf_offset == 0) return -1;
    
    page* leaf = load_page(leaf_offset);
    bool found = false;
    for (int i = 0; i < leaf->num_of_keys; i++) {
        if (leaf->records[i].key == key) {
            found = true; break;
        }
    }
    free(leaf);
    
    if (!found) return -1;
    return delete_entry(leaf_offset, key);
}
์ตœ๊ทผ ์ˆ˜์ •: 26. 6. 12. ์˜คํ›„ 3:28
Contributors: kmbzn, Claude Sonnet 4.6

BUILT WITH

CloudflareNode.jsGitHubGitVue.jsJavaScriptVSCodenpm

All trademarks and logos are property of their respective owners.
ยฉ 2026 kmbzn ยท MIT License