DeveloperBreeze

By default, MySQL stores all its data in /var/lib/mysql. This tutorial explains how to safely move the MySQL data directory to a new location (e.g., another disk or partition) on Ubuntu 25.04.

🔧 Step 1: Stop the MySQL Service

Before making any changes, stop the MySQL service:

sudo systemctl stop mysql

🔧 Step 2: Move the Existing Data Directory

Choose your new location, for example /mnt/data/mysql, and move the current data:

sudo mv /var/lib/mysql /mnt/data/mysql

> This moves all database files including system schemas like mysql and performance_schema.


🔧 Step 3: Set Correct Permissions

Ensure MySQL can access the new directory:

sudo chown -R mysql:mysql /mnt/data/mysql

🔧 Step 4: Update MySQL Configuration

Edit the MySQL configuration file:

sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf

Find the line:

datadir = /var/lib/mysql

Change it to:

datadir = /mnt/data/mysql

Save and exit.


🔧 Step 5: (If AppArmor is Enabled) Add Access Rules

AppArmor may block MySQL from accessing the new path.

Edit AppArmor profile for MySQL:

sudo nano /etc/apparmor.d/usr.sbin.mysqld

Add these lines before the closing }:

/mnt/data/mysql/ r,
/mnt/data/mysql/** rwk,

Then reload AppArmor:

sudo apparmor_parser -r /etc/apparmor.d/usr.sbin.mysqld

🔧 Step 6: Fix MySQL Socket Directory (Optional)

If needed, recreate the MySQL socket directory:

sudo mkdir -p /var/run/mysqld
sudo chown mysql:mysql /var/run/mysqld

🔧 Step 7: Restart MySQL

sudo systemctl start mysql

✅ Step 8: Verify the New Data Directory

Check that MySQL is using the new path:

mysql -u root -p -e "SHOW VARIABLES LIKE 'datadir';"

You should see:

+---------------+------------------+
| Variable_name | Value            |
+---------------+------------------+
| datadir       | /mnt/data/mysql/ |
+---------------+------------------+

Continue Reading

Handpicked posts just for you — based on your current read.

Building a Real-Time Object Detection Web App with TensorFlow.js and p5.js

let video;
let detector;
let detections = [];

function setup() {
  // Create the canvas to match the video dimensions
  createCanvas(640, 480);
  // Capture video from the webcam
  video = createCapture(VIDEO);
  video.size(640, 480);
  video.hide();

  // Load the pre-trained COCO-SSD model
  cocoSsd.load().then(model => {
    detector = model;
    console.log("Model Loaded!");
    // Begin detecting objects every frame
    detectObjects();
  });
}

function detectObjects() {
  detector.detect(video.elt).then(results => {
    detections = results;
    // Continue detection in a loop
    detectObjects();
  });
}

function draw() {
  // Draw the video
  image(video, 0, 0);

  // Draw detection boxes and labels if available
  if (detections) {
    for (let i = 0; i < detections.length; i++) {
      let object = detections[i];
      stroke(0, 255, 0);
      strokeWeight(2);
      noFill();
      rect(object.bbox[0], object.bbox[1], object.bbox[2], object.bbox[3]);
      noStroke();
      fill(0, 255, 0);
      textSize(16);
      text(object.class, object.bbox[0] + 4, object.bbox[1] + 16);
    }
  }
}
  • Setup: The setup function initializes the canvas and video capture. The video is hidden by p5.js’s default element so that we can draw it onto the canvas manually.
  • Model Loading: We load the COCO-SSD model asynchronously. Once the model is ready, we start continuous object detection by calling detectObjects().
  • Detection Loop: The detectObjects function uses the loaded model to analyze the current video frame and stores the detection results. It recursively calls itself so that new frames are analyzed continuously.
  • Drawing: In the draw loop, the video feed is displayed and for each detected object, a rectangle and label are drawn. The bounding box coordinates and object class are provided by the model.

Feb 12, 2025 Tutorial

Implementing a Domain-Specific Language (DSL) with LLVM and C++

#include "DSL/Lexer.h"
#include <cctype>
#include <cstdlib>

Lexer::Lexer(const std::string& input) : input(input) {}

char Lexer::currentChar() {
    if (pos < input.size()) {
        return input[pos];
    }
    return '\0';
}

void Lexer::advance() {
    pos++;
}

void Lexer::skipWhitespace() {
    while (std::isspace(currentChar())) {
        advance();
    }
}

Token Lexer::number() {
    size_t start = pos;
    while (std::isdigit(currentChar()) || currentChar() == '.') {
        advance();
    }
    std::string numStr = input.substr(start, pos - start);
    double value = std::strtod(numStr.c_str(), nullptr);
    return { TokenType::Number, numStr, value };
}

Token Lexer::getNextToken() {
    skipWhitespace();

    char current = currentChar();

    if (current == '\0') {
        return { TokenType::EndOfFile, "", 0 };
    }
    if (std::isdigit(current) || current == '.') {
        return number();
    }

    Token token;
    token.text = std::string(1, current);
    token.value = 0;
    switch (current) {
        case '+': token.type = TokenType::Plus; break;
        case '-': token.type = TokenType::Minus; break;
        case '*': token.type = TokenType::Asterisk; break;
        case '/': token.type = TokenType::Slash; break;
        case '(': token.type = TokenType::LParen; break;
        case ')': token.type = TokenType::RParen; break;
        default: token.type = TokenType::Invalid; break;
    }
    advance();
    return token;
}

We’ll implement a recursive-descent parser that constructs an Abstract Syntax Tree (AST) from tokens. Our grammar is defined with standard operator precedence:

Feb 12, 2025 Tutorial

Discussion 0

Please sign in to join the discussion.

No comments yet. Start the discussion!